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