Remove the RCSID macro
[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/stds.h>
36 #include <afs/cmd.h>
37
38 #include <stdio.h>
39
40 #include "rx_user.h"
41 #include "rx_clock.h"
42 #include "rx_queue.h"
43 #include "rx.h"
44 #include "rx_globals.h"
45
46
47 #define TIMEOUT     20
48
49 extern struct hostent *hostutil_GetHostByName();
50
51 static short
52 PortNumber(aport)
53      register char *aport;
54 {
55     register int tc;
56     register short total;
57
58     total = 0;
59     while (tc = *aport++) {
60         if (tc < '0' || tc > '9')
61             return -1;          /* bad port number */
62         total *= 10;
63         total += tc - (int)'0';
64     }
65     return htons(total);
66 }
67
68 static short
69 PortName(aname)
70      register char *aname;
71 {
72     register struct servent *ts;
73     ts = getservbyname(aname, NULL);
74     if (!ts)
75         return -1;
76     return ts->s_port;          /* returns it in network byte order */
77 }
78
79 int
80 MainCommand(struct cmd_syndesc *as, void *arock)
81 {
82     register int i;
83     osi_socket s;
84     int j;
85     struct sockaddr_in taddr;
86     afs_int32 host;
87     struct in_addr hostAddr;
88     short port;
89     struct hostent *th;
90     register afs_int32 code;
91     int nodally;
92     int allconns;
93     int rxstats;
94     int onlyClient, onlyServer;
95     afs_int32 onlyHost;
96     short onlyPort;
97     int onlyAuth;
98     int flag;
99     int dallyCounter;
100     int withSecStats;
101     int withAllConn;
102     int withRxStats;
103     int withWaiters;
104     int withIdleThreads;
105     int withWaited;
106     int withPeers;
107     int withPackets;
108     struct rx_debugStats tstats;
109     char *portName, *hostName;
110     char hoststr[20];
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 = NULL;
140
141     if (as->parms[1].items)
142         portName = as->parms[1].items->data;
143     else
144         portName = NULL;
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
155         onlyPort = -1;
156
157     if (as->parms[8].items) {
158         char *name = as->parms[8].items->data;
159         struct hostent *th;
160         th = hostutil_GetHostByName(name);
161         if (!th) {
162             printf("rxdebug: host %s not found in host table\n", name);
163             exit(1);
164         }
165         memcpy(&onlyHost, th->h_addr, sizeof(afs_int32));
166     } else
167         onlyHost = -1;
168
169     if (as->parms[9].items) {
170         char *name = as->parms[9].items->data;
171         if (strcmp(name, "clear") == 0)
172             onlyAuth = 0;
173         else if (strcmp(name, "auth") == 0)
174             onlyAuth = 1;
175         else if (strcmp(name, "crypt") == 0)
176             onlyAuth = 2;
177         else if ((strcmp(name, "null") == 0) || (strcmp(name, "none") == 0)
178                  || (strncmp(name, "noauth", 6) == 0)
179                  || (strncmp(name, "unauth", 6) == 0))
180             onlyAuth = -1;
181         else {
182             fprintf(stderr, "Unknown authentication level: %s\n", name);
183             exit(1);
184         }
185     } else
186         onlyAuth = 999;
187
188     /* lookup host */
189     if (hostName) {
190         th = hostutil_GetHostByName(hostName);
191         if (!th) {
192             printf("rxdebug: host %s not found in host table\n", hostName);
193             exit(1);
194         }
195         memcpy(&host, th->h_addr, sizeof(afs_int32));
196     } else
197         host = htonl(0x7f000001);       /* IP localhost */
198
199     if (!portName)
200         port = htons(7000);     /* default is fileserver */
201     else {
202         if ((port = PortNumber(portName)) == -1)
203             port = PortName(portName);
204         if (port == -1) {
205             printf("rxdebug: can't resolve port name %s\n", portName);
206             exit(1);
207         }
208     }
209
210     dallyCounter = 0;
211
212     hostAddr.s_addr = host;
213     afs_inet_ntoa_r(hostAddr.s_addr, hoststr);
214     printf("Trying %s (port %d):\n", hoststr, ntohs(port));
215     s = socket(AF_INET, SOCK_DGRAM, 0);
216     taddr.sin_family = AF_INET;
217     taddr.sin_port = 0;
218     taddr.sin_addr.s_addr = 0;
219 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
220     taddr.sin_len = sizeof(struct sockaddr_in);
221 #endif
222     code = bind(s, (struct sockaddr *)&taddr, sizeof(struct sockaddr_in));
223     if (code) {
224         perror("bind");
225         exit(1);
226     }
227
228     if (version_flag) {
229
230         code = rx_GetServerVersion(s, host, port, length, version);
231         if (code < 0) {
232             printf("get version call failed with code %d, errno %d\n", code,
233                    errno);
234             exit(1);
235         }
236         printf("AFS version: %s\n", version);
237         fflush(stdout);
238
239         exit(0);
240
241     }
242
243
244     code = rx_GetServerDebug(s, host, port, &tstats, &supportedDebugValues);
245     if (code < 0) {
246         printf("getstats call failed with code %d\n", code);
247         exit(1);
248     }
249
250     withSecStats = (supportedDebugValues & RX_SERVER_DEBUG_SEC_STATS);
251     withAllConn = (supportedDebugValues & RX_SERVER_DEBUG_ALL_CONN);
252     withRxStats = (supportedDebugValues & RX_SERVER_DEBUG_RX_STATS);
253     withWaiters = (supportedDebugValues & RX_SERVER_DEBUG_WAITER_CNT);
254     withIdleThreads = (supportedDebugValues & RX_SERVER_DEBUG_IDLE_THREADS);
255     withWaited = (supportedDebugValues & RX_SERVER_DEBUG_WAITED_CNT);
256     withPeers = (supportedDebugValues & RX_SERVER_DEBUG_ALL_PEER);
257     withPackets = (supportedDebugValues & RX_SERVER_DEBUG_PACKETS_CNT);
258
259     if (withPackets)
260         printf("Free packets: %d/%d, packet reclaims: %d, calls: %d, used FDs: %d\n",
261                tstats.nFreePackets, tstats.nPackets, tstats.packetReclaims, 
262                tstats.callsExecuted, tstats.usedFDs);
263     else
264         printf("Free packets: %d, packet reclaims: %d, calls: %d, used FDs: %d\n",
265                tstats.nFreePackets, tstats.packetReclaims, tstats.callsExecuted,
266                tstats.usedFDs);
267     if (!tstats.waitingForPackets)
268         printf("not ");
269     printf("waiting for packets.\n");
270     if (withWaiters)
271         printf("%d calls waiting for a thread\n", tstats.nWaiting);
272     if (withIdleThreads)
273         printf("%d threads are idle\n", tstats.idleThreads);
274     if (withWaited)
275         printf("%d calls have waited for a thread\n", tstats.nWaited);
276
277     if (rxstats) {
278         if (!withRxStats) {
279           noRxStats:
280             withRxStats = 0;
281             fprintf(stderr,
282                     "WARNING: Server doesn't support retrieval of Rx statistics\n");
283         } else {
284             struct rx_statistics rxstats;
285
286             /* should gracefully handle the case where rx_stats grows */
287             code =
288                 rx_GetServerStats(s, host, port, &rxstats,
289                                   &supportedStatValues);
290             if (code < 0) {
291                 printf("rxstats call failed with code %d\n", code);
292                 exit(1);
293             }
294             if (code != sizeof(rxstats)) {
295                 if ((((struct rx_debugIn *)(&rxstats))->type ==
296                      RX_DEBUGI_BADTYPE))
297                     goto noRxStats;
298                 printf
299                     ("WARNING: returned Rx statistics of unexpected size (got %d)\n",
300                      code);
301                 /* handle other versions?... */
302             }
303
304             rx_PrintTheseStats(stdout, &rxstats, sizeof(rxstats),
305                                tstats.nFreePackets, tstats.version);
306         }
307     }
308
309     if (!noConns) {
310         if (allconns) {
311             if (!withAllConn)
312                 fprintf(stderr,
313                         "WARNING: Server doesn't support retrieval of all connections,\n         getting only interesting instead.\n");
314         }
315
316         if (onlyServer)
317             printf("Showing only server connections\n");
318         if (onlyClient)
319             printf("Showing only client connections\n");
320         if (onlyAuth != 999) {
321             static char *name[] =
322                 { "unauthenticated", "rxkad_clear", "rxkad_auth",
323                 "rxkad_crypt"
324             };
325             printf("Showing only %s connections\n", name[onlyAuth + 1]);
326         }
327         if (onlyHost != -1) {
328             hostAddr.s_addr = onlyHost;
329             afs_inet_ntoa_r(hostAddr.s_addr, hoststr);
330             printf("Showing only connections from host %s\n",
331                    hoststr);
332         }
333         if (onlyPort != -1)
334             printf("Showing only connections on port %u\n", ntohs(onlyPort));
335
336         for (i = 0;; i++) {
337             code =
338                 rx_GetServerConnections(s, host, port, &nextconn, allconns,
339                                         supportedDebugValues, &tconn,
340                                         &supportedConnValues);
341             if (code < 0) {
342                 printf("getconn call failed with code %d\n", code);
343                 break;
344             }
345             if (tconn.cid == (afs_int32) 0xffffffff) {
346                 printf("Done.\n");
347                 break;
348             }
349
350             /* see if we're in nodally mode and all calls are dallying */
351             if (nodally) {
352                 flag = 0;
353                 for (j = 0; j < RX_MAXCALLS; j++) {
354                     if (tconn.callState[j] != RX_STATE_NOTINIT
355                         && tconn.callState[j] != RX_STATE_DALLY) {
356                         flag = 1;
357                         break;
358                     }
359                 }
360                 if (flag == 0) {
361                     /* this call looks too ordinary, bump skipped count and go
362                      * around again */
363                     dallyCounter++;
364                     continue;
365                 }
366             }
367             if ((onlyHost != -1) && (onlyHost != tconn.host))
368                 continue;
369             if ((onlyPort != -1) && (onlyPort != tconn.port))
370                 continue;
371             if (onlyServer && (tconn.type != RX_SERVER_CONNECTION))
372                 continue;
373             if (onlyClient && (tconn.type != RX_CLIENT_CONNECTION))
374                 continue;
375             if (onlyAuth != 999) {
376                 if (onlyAuth == -1) {
377                     if (tconn.securityIndex != 0)
378                         continue;
379                 } else {
380                     if (tconn.securityIndex != 2)
381                         continue;
382                     if (withSecStats && (tconn.secStats.type == 3)
383                         && (tconn.secStats.level != onlyAuth))
384                         continue;
385                 }
386             }
387
388             /* now display the connection */
389             hostAddr.s_addr = tconn.host;
390             afs_inet_ntoa_r(hostAddr.s_addr, hoststr);
391             printf("Connection from host %s, port %hu, ", hoststr,
392                    ntohs(tconn.port));
393             if (tconn.epoch)
394                 printf("Cuid %x/%x", tconn.epoch, tconn.cid);
395             else
396                 printf("cid %x", tconn.cid);
397             if (tconn.error)
398                 printf(", error %d", tconn.error);
399             printf("\n  serial %d, ", tconn.serial);
400             printf(" natMTU %d, ", tconn.natMTU);
401
402             if (tconn.flags) {
403                 printf("flags");
404                 if (tconn.flags & RX_CONN_MAKECALL_WAITING)
405                     printf(" MAKECALL_WAITING");
406                 if (tconn.flags & RX_CONN_DESTROY_ME)
407                     printf(" DESTROYED");
408                 if (tconn.flags & RX_CONN_USING_PACKET_CKSUM)
409                     printf(" pktCksum");
410                 if (tconn.flags & RX_CONN_KNOW_WINDOW)
411                     printf(" knowWindow");
412                 if (tconn.flags & RX_CONN_RESET)
413                     printf(" reset");
414                 if (tconn.flags & RX_CONN_BUSY)
415                     printf(" busy");
416                 if (tconn.flags & RX_CONN_ATTACHWAIT)
417                     printf(" attachWait");
418                 printf(", ");
419             }
420             printf("security index %d, ", tconn.securityIndex);
421             if (tconn.type == RX_CLIENT_CONNECTION)
422                 printf("client conn\n");
423             else
424                 printf("server conn\n");
425
426             if (withSecStats) {
427                 switch ((int)tconn.secStats.type) {
428                 case 0:
429                     if (tconn.securityIndex == 2)
430                         printf
431                             ("  no GetStats procedure for security object\n");
432                     break;
433                 case 1:
434                     printf("  rxnull level=%d, flags=%d\n",
435                            tconn.secStats.level, tconn.secStats.flags);
436                     break;
437                 case 2:
438                     printf("  rxvab level=%d, flags=%d\n",
439                            tconn.secStats.level, tconn.secStats.flags);
440                     break;
441                 case 3:{
442                         char *level;
443                         char flags = tconn.secStats.flags;
444                         if (tconn.secStats.level == 0)
445                             level = "clear";
446                         else if (tconn.secStats.level == 1)
447                             level = "auth";
448                         else if (tconn.secStats.level == 2)
449                             level = "crypt";
450                         else
451                             level = "unknown";
452                         printf("  rxkad: level %s", level);
453                         if (flags)
454                             printf(", flags");
455                         if (flags & 1)
456                             printf(" unalloc");
457                         if (flags & 2)
458                             printf(" authenticated");
459                         if (flags & 4)
460                             printf(" expired");
461                         if (flags & 8)
462                             printf(" pktCksum");
463                         if (tconn.secStats.expires)
464                             /* Apparently due to a bug in the RT compiler that
465                              * prevents (afs_uint32)0xffffffff => (double) from working,
466                              * this code produces negative lifetimes when run on the
467                              * RT. */
468                             printf(", expires in %.1f hours",
469                                    ((afs_uint32) tconn.secStats.expires -
470                                     time(0)) / 3600.0);
471                         if (!(flags & 1)) {
472                             printf("\n  Received %u bytes in %u packets\n",
473                                    tconn.secStats.bytesReceived,
474                                    tconn.secStats.packetsReceived);
475                             printf("  Sent %u bytes in %u packets\n",
476                                    tconn.secStats.bytesSent,
477                                    tconn.secStats.packetsSent);
478                         } else
479                             printf("\n");
480                         break;
481                     }
482
483                 default:
484                     printf("  unknown\n");
485                 }
486             }
487
488             for (j = 0; j < RX_MAXCALLS; j++) {
489                 printf("    call %d: # %d, state ", j, tconn.callNumber[j]);
490                 if (tconn.callState[j] == RX_STATE_NOTINIT) {
491                     printf("not initialized\n");
492                     continue;
493                 } else if (tconn.callState[j] == RX_STATE_PRECALL)
494                     printf("precall, ");
495                 else if (tconn.callState[j] == RX_STATE_ACTIVE)
496                     printf("active, ");
497                 else if (tconn.callState[j] == RX_STATE_DALLY)
498                     printf("dally, ");
499                 else if (tconn.callState[j] == RX_STATE_HOLD)
500                     printf("hold, ");
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(argc, argv)
597      int argc;
598      char **argv;
599 {
600     struct cmd_syndesc *ts;
601
602 #ifdef RXDEBUG
603     rxi_DebugInit();
604 #endif
605 #ifdef AFS_NT40_ENV
606     if (afs_winsockInit() < 0) {
607         printf("%s: Couldn't initialize winsock. Exiting...\n", argv[0]);
608         return 1;
609     }
610 #endif
611
612     ts = cmd_CreateSyntax(NULL, MainCommand, NULL, "probe RX server");
613     cmd_AddParm(ts, "-servers", CMD_SINGLE, CMD_REQUIRED, "server machine");
614     cmd_AddParm(ts, "-port", CMD_SINGLE, CMD_OPTIONAL, "IP port");
615     cmd_AddParm(ts, "-nodally", CMD_FLAG, CMD_OPTIONAL,
616                 "don't show dallying conns");
617     cmd_AddParm(ts, "-allconnections", CMD_FLAG, CMD_OPTIONAL,
618                 "don't filter out uninteresting connections on server");
619     cmd_AddParm(ts, "-rxstats", CMD_FLAG, CMD_OPTIONAL, "show Rx statistics");
620     cmd_AddParm(ts, "-onlyserver", CMD_FLAG, CMD_OPTIONAL,
621                 "only show server conns");
622     cmd_AddParm(ts, "-onlyclient", CMD_FLAG, CMD_OPTIONAL,
623                 "only show client conns");
624     cmd_AddParm(ts, "-onlyport", CMD_SINGLE, CMD_OPTIONAL,
625                 "show only <port>");
626     cmd_AddParm(ts, "-onlyhost", CMD_SINGLE, CMD_OPTIONAL,
627                 "show only <host>");
628     cmd_AddParm(ts, "-onlyauth", CMD_SINGLE, CMD_OPTIONAL,
629                 "show only <auth level>");
630
631     cmd_AddParm(ts, "-version", CMD_FLAG, CMD_OPTIONAL,
632                 "show AFS version id");
633     cmd_AddParm(ts, "-noconns", CMD_FLAG, CMD_OPTIONAL,
634                 "show no connections");
635     cmd_AddParm(ts, "-peers", CMD_FLAG, CMD_OPTIONAL, "show peers");
636     cmd_AddParm(ts, "-long", CMD_FLAG, CMD_OPTIONAL, "detailed output");
637
638     cmd_Dispatch(argc, argv);
639     exit(0);
640 }