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