7b23cbca552c2d816626a9575c675091ee47bd84
[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
217         code = rx_GetServerVersion(s, host, port, length, version);
218         if (code < 0) {
219             printf("get version call failed with code %d, errno %d\n", code,
220                    errno);
221             exit(1);
222         }
223         printf("AFS version: %s\n", version);
224         fflush(stdout);
225
226         exit(0);
227
228     }
229
230
231     code = rx_GetServerDebug(s, host, port, &tstats, &supportedDebugValues);
232     if (code < 0) {
233         printf("getstats call failed with code %d\n", code);
234         exit(1);
235     }
236
237     withSecStats = (supportedDebugValues & RX_SERVER_DEBUG_SEC_STATS);
238     withAllConn = (supportedDebugValues & RX_SERVER_DEBUG_ALL_CONN);
239     withRxStats = (supportedDebugValues & RX_SERVER_DEBUG_RX_STATS);
240     withWaiters = (supportedDebugValues & RX_SERVER_DEBUG_WAITER_CNT);
241     withIdleThreads = (supportedDebugValues & RX_SERVER_DEBUG_IDLE_THREADS);
242     withWaited = (supportedDebugValues & RX_SERVER_DEBUG_WAITED_CNT);
243     withPeers = (supportedDebugValues & RX_SERVER_DEBUG_ALL_PEER);
244     withPackets = (supportedDebugValues & RX_SERVER_DEBUG_PACKETS_CNT);
245
246     if (withPackets)
247         printf("Free packets: %d/%d, packet reclaims: %d, calls: %d, used FDs: %d\n",
248                tstats.nFreePackets, tstats.nPackets, tstats.packetReclaims,
249                tstats.callsExecuted, tstats.usedFDs);
250     else
251         printf("Free packets: %d, packet reclaims: %d, calls: %d, used FDs: %d\n",
252                tstats.nFreePackets, tstats.packetReclaims, tstats.callsExecuted,
253                tstats.usedFDs);
254     if (!tstats.waitingForPackets)
255         printf("not ");
256     printf("waiting for packets.\n");
257     if (withWaiters)
258         printf("%d calls waiting for a thread\n", tstats.nWaiting);
259     if (withIdleThreads)
260         printf("%d threads are idle\n", tstats.idleThreads);
261     if (withWaited)
262         printf("%d calls have waited for a thread\n", tstats.nWaited);
263
264     if (rxstats) {
265         if (!withRxStats) {
266           noRxStats:
267             withRxStats = 0;
268             fprintf(stderr,
269                     "WARNING: Server doesn't support retrieval of Rx statistics\n");
270         } else {
271             struct rx_statistics rxstats;
272
273             /* should gracefully handle the case where rx_stats grows */
274             code =
275                 rx_GetServerStats(s, host, port, &rxstats,
276                                   &supportedStatValues);
277             if (code < 0) {
278                 printf("rxstats call failed with code %d\n", code);
279                 exit(1);
280             }
281             if (code != sizeof(rxstats)) {
282                 struct rx_debugIn debug;
283                 memcpy(&debug, &rxstats, sizeof(debug));
284                 if (debug.type == RX_DEBUGI_BADTYPE)
285                     goto noRxStats;
286                 printf
287                     ("WARNING: returned Rx statistics of unexpected size (got %d)\n",
288                      code);
289                 /* handle other versions?... */
290             }
291
292             rx_PrintTheseStats(stdout, &rxstats, sizeof(rxstats),
293                                tstats.nFreePackets, tstats.version);
294         }
295     }
296
297     if (!noConns) {
298         if (allconns) {
299             if (!withAllConn)
300                 fprintf(stderr,
301                         "WARNING: Server doesn't support retrieval of all connections,\n         getting only interesting instead.\n");
302         }
303
304         if (onlyServer)
305             printf("Showing only server connections\n");
306         if (onlyClient)
307             printf("Showing only client connections\n");
308         if (onlyAuth != 999) {
309             static char *name[] =
310                 { "unauthenticated", "rxkad_clear", "rxkad_auth",
311                 "rxkad_crypt"
312             };
313             printf("Showing only %s connections\n", name[onlyAuth + 1]);
314         }
315         if (onlyHost != -1) {
316             hostAddr.s_addr = onlyHost;
317             afs_inet_ntoa_r(hostAddr.s_addr, hoststr);
318             printf("Showing only connections from host %s\n",
319                    hoststr);
320         }
321         if (onlyPort != -1)
322             printf("Showing only connections on port %u\n", ntohs(onlyPort));
323
324         for (i = 0;; i++) {
325             code =
326                 rx_GetServerConnections(s, host, port, &nextconn, allconns,
327                                         supportedDebugValues, &tconn,
328                                         &supportedConnValues);
329             if (code < 0) {
330                 printf("getconn call failed with code %d\n", code);
331                 break;
332             }
333             if (tconn.cid == (afs_int32) 0xffffffff) {
334                 printf("Done.\n");
335                 break;
336             }
337
338             /* see if we're in nodally mode and all calls are dallying */
339             if (nodally) {
340                 flag = 0;
341                 for (j = 0; j < RX_MAXCALLS; j++) {
342                     if (tconn.callState[j] != RX_STATE_NOTINIT
343                         && tconn.callState[j] != RX_STATE_DALLY) {
344                         flag = 1;
345                         break;
346                     }
347                 }
348                 if (flag == 0) {
349                     /* this call looks too ordinary, bump skipped count and go
350                      * around again */
351                     dallyCounter++;
352                     continue;
353                 }
354             }
355             if ((onlyHost != -1) && (onlyHost != tconn.host))
356                 continue;
357             if ((onlyPort != -1) && (onlyPort != tconn.port))
358                 continue;
359             if (onlyServer && (tconn.type != RX_SERVER_CONNECTION))
360                 continue;
361             if (onlyClient && (tconn.type != RX_CLIENT_CONNECTION))
362                 continue;
363             if (onlyAuth != 999) {
364                 if (onlyAuth == -1) {
365                     if (tconn.securityIndex != RX_SECIDX_NULL)
366                         continue;
367                 } else {
368                     if (tconn.securityIndex != RX_SECIDX_KAD)
369                         continue;
370                     if (withSecStats && (tconn.secStats.type == RX_SECTYPE_KAD)
371                         && (tconn.secStats.level != onlyAuth))
372                         continue;
373                 }
374             }
375
376             /* now display the connection */
377             hostAddr.s_addr = tconn.host;
378             afs_inet_ntoa_r(hostAddr.s_addr, hoststr);
379             printf("Connection from host %s, port %hu, ", hoststr,
380                    ntohs(tconn.port));
381             if (tconn.epoch)
382                 printf("Cuid %x/%x", tconn.epoch, tconn.cid);
383             else
384                 printf("cid %x", tconn.cid);
385             if (tconn.error)
386                 printf(", error %d", tconn.error);
387             printf("\n  serial %d, ", tconn.serial);
388             printf(" natMTU %d, ", tconn.natMTU);
389
390             if (tconn.flags) {
391                 printf("flags");
392                 if (tconn.flags & RX_CONN_MAKECALL_WAITING)
393                     printf(" MAKECALL_WAITING");
394                 if (tconn.flags & RX_CONN_DESTROY_ME)
395                     printf(" DESTROYED");
396                 if (tconn.flags & RX_CONN_USING_PACKET_CKSUM)
397                     printf(" pktCksum");
398                 if (tconn.flags & RX_CONN_KNOW_WINDOW)
399                     printf(" knowWindow");
400                 if (tconn.flags & RX_CONN_RESET)
401                     printf(" reset");
402                 if (tconn.flags & RX_CONN_BUSY)
403                     printf(" busy");
404                 if (tconn.flags & RX_CONN_ATTACHWAIT)
405                     printf(" attachWait");
406                 printf(", ");
407             }
408             printf("security index %d, ", tconn.securityIndex);
409             if (tconn.type == RX_CLIENT_CONNECTION)
410                 printf("client conn\n");
411             else
412                 printf("server conn\n");
413
414             if (withSecStats) {
415                 switch ((int)tconn.secStats.type) {
416                 case RX_SECTYPE_UNK:
417                     if (tconn.securityIndex == RX_SECIDX_KAD)
418                         printf
419                             ("  no GetStats procedure for security object\n");
420                     break;
421                 case RX_SECTYPE_NULL:
422                     printf("  rxnull level=%d, flags=%d\n",
423                            tconn.secStats.level, tconn.secStats.flags);
424                     break;
425                 case RX_SECTYPE_VAB:
426                     printf("  rxvab level=%d, flags=%d\n",
427                            tconn.secStats.level, tconn.secStats.flags);
428                     break;
429                 case RX_SECTYPE_KAD:{
430                         char *level;
431                         char flags = tconn.secStats.flags;
432                         if (tconn.secStats.level == 0)
433                             level = "clear";
434                         else if (tconn.secStats.level == 1)
435                             level = "auth";
436                         else if (tconn.secStats.level == 2)
437                             level = "crypt";
438                         else
439                             level = "unknown";
440                         printf("  rxkad: level %s", level);
441                         if (flags)
442                             printf(", flags");
443                         if (flags & 1)
444                             printf(" unalloc");
445                         if (flags & 2)
446                             printf(" authenticated");
447                         if (flags & 4)
448                             printf(" expired");
449                         if (flags & 8)
450                             printf(" pktCksum");
451                         if (tconn.secStats.expires)
452                             /* Apparently due to a bug in the RT compiler that
453                              * prevents (afs_uint32)0xffffffff => (double) from working,
454                              * this code produces negative lifetimes when run on the
455                              * RT. */
456                             printf(", expires in %.1f hours",
457                                    ((afs_uint32) tconn.secStats.expires -
458                                     time(0)) / 3600.0);
459                         if (!(flags & 1)) {
460                             printf("\n  Received %u bytes in %u packets\n",
461                                    tconn.secStats.bytesReceived,
462                                    tconn.secStats.packetsReceived);
463                             printf("  Sent %u bytes in %u packets\n",
464                                    tconn.secStats.bytesSent,
465                                    tconn.secStats.packetsSent);
466                         } else
467                             printf("\n");
468                         break;
469                     }
470
471                 default:
472                     printf("  unknown\n");
473                 }
474             }
475
476             for (j = 0; j < RX_MAXCALLS; j++) {
477                 printf("    call %d: # %d, state ", j, tconn.callNumber[j]);
478                 if (tconn.callState[j] == RX_STATE_NOTINIT) {
479                     printf("not initialized\n");
480                     continue;
481                 } else if (tconn.callState[j] == RX_STATE_PRECALL)
482                     printf("precall, ");
483                 else if (tconn.callState[j] == RX_STATE_ACTIVE)
484                     printf("active, ");
485                 else if (tconn.callState[j] == RX_STATE_DALLY)
486                     printf("dally, ");
487                 else if (tconn.callState[j] == RX_STATE_HOLD)
488                     printf("hold, ");
489                 else if (tconn.callState[j] == RX_STATE_RESET)
490                     printf("reset, ");
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 %u\tpacket resends %u\n", tpeer.nSent,
557                    tpeer.reSends);
558             printf("\tbytes sent high %u low %u\n", tpeer.bytesSent.high,
559                    tpeer.bytesSent.low);
560             printf("\tbytes received high %u low %u\n",
561                    tpeer.bytesReceived.high, tpeer.bytesReceived.low);
562             printf("\trtt %u msec, rtt_dev %u msec\n", tpeer.rtt >> 3,
563                    tpeer.rtt_dev >> 2);
564             printf("\ttimeout %u.%03u sec\n", tpeer.timeout.sec,
565                    tpeer.timeout.usec / 1000);
566             if (!showLong)
567                 continue;
568
569             printf("\tin/out packet skew: %d/%d\n", tpeer.inPacketSkew,
570                     tpeer.outPacketSkew);
571             printf("\tcongestion window %d, MTU %d\n", tpeer.cwind,
572                    tpeer.MTU);
573             printf("\tcurrent/if/max jumbogram size: %d/%d/%d\n",
574                    tpeer.nDgramPackets, tpeer.ifDgramPackets,
575                    tpeer.maxDgramPackets);
576         }
577     }
578     exit(0);
579 }
580
581 /* simple main program */
582 #ifndef AFS_NT40_ENV
583 #include "AFS_component_version_number.c"
584 #endif
585 int
586 main(int argc, char **argv)
587 {
588     struct cmd_syndesc *ts;
589
590 #ifdef RXDEBUG
591     rxi_DebugInit();
592 #endif
593 #ifdef AFS_NT40_ENV
594     if (afs_winsockInit() < 0) {
595         printf("%s: Couldn't initialize winsock. Exiting...\n", argv[0]);
596         return 1;
597     }
598 #endif
599
600     ts = cmd_CreateSyntax(NULL, MainCommand, NULL, "probe RX server");
601     cmd_AddParm(ts, "-servers", CMD_SINGLE, CMD_REQUIRED, "server machine");
602     cmd_AddParm(ts, "-port", CMD_SINGLE, CMD_OPTIONAL, "IP port");
603     cmd_AddParm(ts, "-nodally", CMD_FLAG, CMD_OPTIONAL,
604                 "don't show dallying conns");
605     cmd_AddParm(ts, "-allconnections", CMD_FLAG, CMD_OPTIONAL,
606                 "don't filter out uninteresting connections on server");
607     cmd_AddParm(ts, "-rxstats", CMD_FLAG, CMD_OPTIONAL, "show Rx statistics");
608     cmd_AddParm(ts, "-onlyserver", CMD_FLAG, CMD_OPTIONAL,
609                 "only show server conns");
610     cmd_AddParm(ts, "-onlyclient", CMD_FLAG, CMD_OPTIONAL,
611                 "only show client conns");
612     cmd_AddParm(ts, "-onlyport", CMD_SINGLE, CMD_OPTIONAL,
613                 "show only <port>");
614     cmd_AddParm(ts, "-onlyhost", CMD_SINGLE, CMD_OPTIONAL,
615                 "show only <host>");
616     cmd_AddParm(ts, "-onlyauth", CMD_SINGLE, CMD_OPTIONAL,
617                 "show only <auth level>");
618
619     cmd_AddParm(ts, "-version", CMD_FLAG, CMD_OPTIONAL,
620                 "show AFS version id");
621     cmd_AddParm(ts, "-noconns", CMD_FLAG, CMD_OPTIONAL,
622                 "show no connections");
623     cmd_AddParm(ts, "-peers", CMD_FLAG, CMD_OPTIONAL, "show peers");
624     cmd_AddParm(ts, "-long", CMD_FLAG, CMD_OPTIONAL, "detailed output");
625
626     cmd_Dispatch(argc, argv);
627     exit(0);
628 }