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