9a35382d0830fb13b8520867b299b1ec18e4c0ec
[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 <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 static short
57 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')
66             return -1;          /* bad port number */
67         total *= 10;
68         total += tc - (int)'0';
69     }
70     return htons(total);
71 }
72
73 static short
74 PortName(aname)
75      register char *aname;
76 {
77     register struct servent *ts;
78     ts = getservbyname(aname, NULL);
79     if (!ts)
80         return -1;
81     return ts->s_port;          /* returns it in network byte order */
82 }
83
84 int
85 MainCommand(as, arock)
86      char *arock;
87      struct cmd_syndesc *as;
88 {
89     register int i;
90     int s;
91     int j;
92     struct sockaddr_in taddr;
93     afs_int32 host;
94     struct in_addr hostAddr;
95     short port;
96     struct hostent *th;
97     register afs_int32 code;
98     int nodally;
99     int allconns;
100     int rxstats;
101     int onlyClient, onlyServer;
102     afs_int32 onlyHost;
103     short onlyPort;
104     int onlyAuth;
105     int flag;
106     int dallyCounter;
107     int withSecStats;
108     int withAllConn;
109     int withRxStats;
110     int withWaiters;
111     int withIdleThreads;
112     int withWaited;
113     int withPeers;
114     struct rx_debugStats tstats;
115     char *portName, *hostName;
116     char hoststr[20];
117     struct rx_debugConn tconn;
118     short noConns;
119     short showPeers;
120     int version_flag;
121     char version[64];
122     afs_int32 length = 64;
123
124     afs_uint32 supportedDebugValues = 0;
125     afs_uint32 supportedStatValues = 0;
126     afs_uint32 supportedConnValues = 0;
127     afs_uint32 supportedPeerValues = 0;
128     afs_int32 nextconn = 0;
129     afs_int32 nextpeer = 0;
130
131     nodally = (as->parms[2].items ? 1 : 0);
132     allconns = (as->parms[3].items ? 1 : 0);
133     rxstats = (as->parms[4].items ? 1 : 0);
134     onlyServer = (as->parms[5].items ? 1 : 0);
135     onlyClient = (as->parms[6].items ? 1 : 0);
136     version_flag = (as->parms[10].items ? 1 : 0);
137     noConns = (as->parms[11].items ? 1 : 0);
138     showPeers = (as->parms[12].items ? 1 : 0);
139
140     if (as->parms[0].items)
141         hostName = as->parms[0].items->data;
142     else
143         hostName = NULL;
144
145     if (as->parms[1].items)
146         portName = as->parms[1].items->data;
147     else
148         portName = NULL;
149
150     if (as->parms[7].items) {
151         char *name = as->parms[7].items->data;
152         if ((onlyPort = PortNumber(name)) == -1)
153             onlyPort = PortName(name);
154         if (onlyPort == -1) {
155             printf("rxdebug: can't resolve port name %s\n", name);
156             exit(1);
157         }
158     } else
159         onlyPort = -1;
160
161     if (as->parms[8].items) {
162         char *name = as->parms[8].items->data;
163         struct hostent *th;
164         th = hostutil_GetHostByName(name);
165         if (!th) {
166             printf("rxdebug: host %s not found in host table\n", name);
167             exit(1);
168         }
169         memcpy(&onlyHost, th->h_addr, sizeof(afs_int32));
170     } else
171         onlyHost = -1;
172
173     if (as->parms[9].items) {
174         char *name = as->parms[9].items->data;
175         if (strcmp(name, "clear") == 0)
176             onlyAuth = 0;
177         else if (strcmp(name, "auth") == 0)
178             onlyAuth = 1;
179         else if (strcmp(name, "crypt") == 0)
180             onlyAuth = 2;
181         else if ((strcmp(name, "null") == 0) || (strcmp(name, "none") == 0)
182                  || (strncmp(name, "noauth", 6) == 0)
183                  || (strncmp(name, "unauth", 6) == 0))
184             onlyAuth = -1;
185         else {
186             fprintf(stderr, "Unknown authentication level: %s\n", name);
187             exit(1);
188         }
189     } else
190         onlyAuth = 999;
191
192     /* lookup host */
193     if (hostName) {
194         th = hostutil_GetHostByName(hostName);
195         if (!th) {
196             printf("rxdebug: host %s not found in host table\n", hostName);
197             exit(1);
198         }
199         memcpy(&host, th->h_addr, sizeof(afs_int32));
200     } else
201         host = htonl(0x7f000001);       /* IP localhost */
202
203     if (!portName)
204         port = htons(7000);     /* default is fileserver */
205     else {
206         if ((port = PortNumber(portName)) == -1)
207             port = PortName(portName);
208         if (port == -1) {
209             printf("rxdebug: can't resolve port name %s\n", portName);
210             exit(1);
211         }
212     }
213
214     dallyCounter = 0;
215
216     hostAddr.s_addr = host;
217     afs_inet_ntoa_r(hostAddr.s_addr, hoststr);
218     printf("Trying %s (port %d):\n", hoststr, ntohs(port));
219     s = socket(AF_INET, SOCK_DGRAM, 0);
220     taddr.sin_family = AF_INET;
221     taddr.sin_port = 0;
222     taddr.sin_addr.s_addr = 0;
223 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
224     taddr.sin_len = sizeof(struct sockaddr_in);
225 #endif
226     code = bind(s, (struct sockaddr *)&taddr, sizeof(struct sockaddr_in));
227     if (code) {
228         perror("bind");
229         exit(1);
230     }
231
232     if (version_flag) {
233
234         code = rx_GetServerVersion(s, host, port, length, version);
235         if (code < 0) {
236             printf("get version call failed with code %d, errno %d\n", code,
237                    errno);
238             exit(1);
239         }
240         printf("AFS version: %s\n", version);
241         fflush(stdout);
242
243         exit(0);
244
245     }
246
247
248     code = rx_GetServerDebug(s, host, port, &tstats, &supportedDebugValues);
249     if (code < 0) {
250         printf("getstats call failed with code %d\n", code);
251         exit(1);
252     }
253
254     withSecStats = (supportedDebugValues & RX_SERVER_DEBUG_SEC_STATS);
255     withAllConn = (supportedDebugValues & RX_SERVER_DEBUG_ALL_CONN);
256     withRxStats = (supportedDebugValues & RX_SERVER_DEBUG_RX_STATS);
257     withWaiters = (supportedDebugValues & RX_SERVER_DEBUG_WAITER_CNT);
258     withIdleThreads = (supportedDebugValues & RX_SERVER_DEBUG_IDLE_THREADS);
259     withWaited = (supportedDebugValues & RX_SERVER_DEBUG_WAITED_CNT);
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     if (withWaited)
273         printf("%d calls have waited for a thread\n", tstats.nWaited);
274
275     if (rxstats) {
276         if (!withRxStats) {
277           noRxStats:
278             withRxStats = 0;
279             fprintf(stderr,
280                     "WARNING: Server doesn't support retrieval of Rx statistics\n");
281         } else {
282             struct rx_stats rxstats;
283
284             /* should gracefully handle the case where rx_stats grows */
285             code =
286                 rx_GetServerStats(s, host, port, &rxstats,
287                                   &supportedStatValues);
288             if (code < 0) {
289                 printf("rxstats call failed with code %d\n", code);
290                 exit(1);
291             }
292             if (code != sizeof(rxstats)) {
293                 if ((((struct rx_debugIn *)(&rxstats))->type ==
294                      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                 printf(", ");
409             }
410             printf("security index %d, ", tconn.securityIndex);
411             if (tconn.type == RX_CLIENT_CONNECTION)
412                 printf("client conn\n");
413             else
414                 printf("server conn\n");
415
416             if (withSecStats) {
417                 switch ((int)tconn.secStats.type) {
418                 case 0:
419                     if (tconn.securityIndex == 2)
420                         printf
421                             ("  no GetStats procedure for security object\n");
422                     break;
423                 case 1:
424                     printf("  rxnull level=%d, flags=%d\n",
425                            tconn.secStats.level, tconn.secStats.flags);
426                     break;
427                 case 2:
428                     printf("  rxvab level=%d, flags=%d\n",
429                            tconn.secStats.level, tconn.secStats.flags);
430                     break;
431                 case 3:{
432                         char *level;
433                         char flags = tconn.secStats.flags;
434                         if (tconn.secStats.level == 0)
435                             level = "clear";
436                         else if (tconn.secStats.level == 1)
437                             level = "auth";
438                         else if (tconn.secStats.level == 2)
439                             level = "crypt";
440                         else
441                             level = "unknown";
442                         printf("  rxkad: level %s", level);
443                         if (flags)
444                             printf(", flags");
445                         if (flags & 1)
446                             printf(" unalloc");
447                         if (flags & 2)
448                             printf(" authenticated");
449                         if (flags & 4)
450                             printf(" expired");
451                         if (flags & 8)
452                             printf(" pktCksum");
453                         if (tconn.secStats.expires)
454                             /* Apparently due to a bug in the RT compiler that
455                              * prevents (afs_uint32)0xffffffff => (double) from working,
456                              * this code produces negative lifetimes when run on the
457                              * RT. */
458                             printf(", expires in %.1f hours",
459                                    ((afs_uint32) tconn.secStats.expires -
460                                     time(0)) / 3600.0);
461                         if (!(flags & 1)) {
462                             printf("\n  Received %d bytes in %d packets\n",
463                                    tconn.secStats.bytesReceived,
464                                    tconn.secStats.packetsReceived);
465                             printf("  Sent %d bytes in %d packets\n",
466                                    tconn.secStats.bytesSent,
467                                    tconn.secStats.packetsSent);
468                         } else
469                             printf("\n");
470                         break;
471                     }
472
473                 default:
474                     printf("  unknown\n");
475                 }
476             }
477
478             for (j = 0; j < RX_MAXCALLS; j++) {
479                 printf("    call %d: # %d, state ", j, tconn.callNumber[j]);
480                 if (tconn.callState[j] == RX_STATE_NOTINIT) {
481                     printf("not initialized\n");
482                     continue;
483                 } else if (tconn.callState[j] == RX_STATE_PRECALL)
484                     printf("precall, ");
485                 else if (tconn.callState[j] == RX_STATE_ACTIVE)
486                     printf("active, ");
487                 else if (tconn.callState[j] == RX_STATE_DALLY)
488                     printf("dally, ");
489                 else if (tconn.callState[j] == RX_STATE_HOLD)
490                     printf("hold, ");
491                 printf("mode: ");
492                 if (tconn.callMode[j] == RX_MODE_SENDING)
493                     printf("sending");
494                 else if (tconn.callMode[j] == RX_MODE_RECEIVING)
495                     printf("receiving");
496                 else if (tconn.callMode[j] == RX_MODE_ERROR)
497                     printf("error");
498                 else if (tconn.callMode[j] == RX_MODE_EOF)
499                     printf("eof");
500                 else
501                     printf("unknown");
502                 if (tconn.callFlags[j]) {
503                     printf(", flags:");
504                     if (tconn.callFlags[j] & RX_CALL_READER_WAIT)
505                         printf(" reader_wait");
506                     if (tconn.callFlags[j] & RX_CALL_WAIT_WINDOW_ALLOC)
507                         printf(" window_alloc");
508                     if (tconn.callFlags[j] & RX_CALL_WAIT_WINDOW_SEND)
509                         printf(" window_send");
510                     if (tconn.callFlags[j] & RX_CALL_WAIT_PACKETS)
511                         printf(" wait_packets");
512                     if (tconn.callFlags[j] & RX_CALL_WAIT_PROC)
513                         printf(" waiting_for_process");
514                     if (tconn.callFlags[j] & RX_CALL_RECEIVE_DONE)
515                         printf(" receive_done");
516                     if (tconn.callFlags[j] & RX_CALL_CLEARED)
517                         printf(" call_cleared");
518                 }
519                 if (tconn.callOther[j] & RX_OTHER_IN)
520                     printf(", has_input_packets");
521                 if (tconn.callOther[j] & RX_OTHER_OUT)
522                     printf(", has_output_packets");
523                 printf("\n");
524             }
525         }
526         if (nodally)
527             printf("Skipped %d dallying connections.\n", dallyCounter);
528     }
529     if (showPeers && withPeers) {
530         for (i = 0;; i++) {
531             struct rx_debugPeer tpeer;
532             code =
533                 rx_GetServerPeers(s, host, port, &nextpeer, allconns, &tpeer,
534                                   &supportedPeerValues);
535             if (code < 0) {
536                 printf("getpeer call failed with code %d\n", code);
537                 break;
538             }
539             if (tpeer.host == 0xffffffff) {
540                 printf("Done.\n");
541                 break;
542             }
543
544             if ((onlyHost != -1) && (onlyHost != tpeer.host))
545                 continue;
546             if ((onlyPort != -1) && (onlyPort != tpeer.port))
547                 continue;
548
549             /* now display the peer */
550             hostAddr.s_addr = tpeer.host;
551             afs_inet_ntoa_r(hostAddr.s_addr, hoststr);
552             printf("Peer at host %s, port %hu\n", hoststr, 
553                    ntohs(tpeer.port));
554             printf("\tifMTU %hu\tnatMTU %hu\tmaxMTU %hu\n", tpeer.ifMTU,
555                    tpeer.natMTU, tpeer.maxMTU);
556             printf("\tpackets sent %d\tpacket resends %d\n", tpeer.nSent,
557                    tpeer.reSends);
558             printf("\tbytes sent high %d low %d\n", tpeer.bytesSent.high,
559                    tpeer.bytesSent.low);
560             printf("\tbytes received high %d low %d\n",
561                    tpeer.bytesReceived.high, tpeer.bytesReceived.low);
562             printf("\trtt %d msec, rtt_dev %d msec\n", tpeer.rtt >> 3,
563                    tpeer.rtt_dev >> 2);
564             printf("\ttimeout %d.%03d sec\n", tpeer.timeout.sec,
565                    tpeer.timeout.usec / 1000);
566         }
567     }
568     exit(0);
569 }
570
571 /* simple main program */
572 #ifndef AFS_NT40_ENV
573 #include "AFS_component_version_number.c"
574 #endif
575 int
576 main(argc, argv)
577      int argc;
578      char **argv;
579 {
580     struct cmd_syndesc *ts;
581
582 #ifdef AFS_NT40_ENV
583     if (afs_winsockInit() < 0) {
584         printf("%s: Couldn't initialize winsock. Exiting...\n", argv[0]);
585         return 1;
586     }
587 #endif
588
589     ts = cmd_CreateSyntax(NULL, MainCommand, 0, "probe RX server");
590     cmd_AddParm(ts, "-servers", CMD_SINGLE, CMD_REQUIRED, "server machine");
591     cmd_AddParm(ts, "-port", CMD_SINGLE, CMD_OPTIONAL, "IP port");
592     cmd_AddParm(ts, "-nodally", CMD_FLAG, CMD_OPTIONAL,
593                 "don't show dallying conns");
594     cmd_AddParm(ts, "-allconnections", CMD_FLAG, CMD_OPTIONAL,
595                 "don't filter out uninteresting connections on server");
596     cmd_AddParm(ts, "-rxstats", CMD_FLAG, CMD_OPTIONAL, "show Rx statistics");
597     cmd_AddParm(ts, "-onlyserver", CMD_FLAG, CMD_OPTIONAL,
598                 "only show server conns");
599     cmd_AddParm(ts, "-onlyclient", CMD_FLAG, CMD_OPTIONAL,
600                 "only show client conns");
601     cmd_AddParm(ts, "-onlyport", CMD_SINGLE, CMD_OPTIONAL,
602                 "show only <port>");
603     cmd_AddParm(ts, "-onlyhost", CMD_SINGLE, CMD_OPTIONAL,
604                 "show only <host>");
605     cmd_AddParm(ts, "-onlyauth", CMD_SINGLE, CMD_OPTIONAL,
606                 "show only <auth level>");
607
608     cmd_AddParm(ts, "-version", CMD_FLAG, CMD_OPTIONAL,
609                 "show AFS version id");
610     cmd_AddParm(ts, "-noconns", CMD_FLAG, CMD_OPTIONAL,
611                 "show no connections");
612     cmd_AddParm(ts, "-peers", CMD_FLAG, CMD_OPTIONAL, "show peers");
613
614     cmd_Dispatch(argc, argv);
615     exit(0);
616 }