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