freebsd-almost-working-client-20020216
[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_STRING_H
34 #include <string.h>
35 #else
36 #ifdef HAVE_STRINGS_H
37 #include <strings.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         memcpy(&onlyHost, th->h_addr, 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         memcpy(&host, th->h_addr, 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 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
211     taddr.sin_len = sizeof(struct sockaddr_in);
212 #endif 
213     code = bind(s, (struct sockaddr *) &taddr, sizeof(struct sockaddr_in));
214     if (code) {
215         perror("bind");
216         exit(1);
217     }
218
219         if(version_flag)
220         {
221     
222                 code = rx_GetServerVersion(s, host, port, length, version);
223                 if (code < 0)
224                 {
225                         printf("get version call failed with code %d, errno %d\n",
226                                 code,errno);
227                         exit(1);
228                 }
229                 printf("AFS version: %s\n",version);fflush(stdout);
230
231                 exit(0);
232
233         }
234
235     
236     code = rx_GetServerDebug(s, host, port, &tstats, &supportedDebugValues);
237     if (code < 0) {
238         printf("getstats call failed with code %d\n", code);
239         exit(1);
240     }
241
242     withSecStats = (supportedDebugValues & RX_SERVER_DEBUG_SEC_STATS);
243     withAllConn = (supportedDebugValues & RX_SERVER_DEBUG_ALL_CONN);
244     withRxStats = (supportedDebugValues & RX_SERVER_DEBUG_RX_STATS);
245     withWaiters = (supportedDebugValues & RX_SERVER_DEBUG_WAITER_CNT);
246     withIdleThreads = (supportedDebugValues & RX_SERVER_DEBUG_IDLE_THREADS);
247     withPeers = (supportedDebugValues & RX_SERVER_DEBUG_ALL_PEER);
248
249     printf("Free packets: %d, packet reclaims: %d, calls: %d, used FDs: %d\n",
250            tstats.nFreePackets, tstats.packetReclaims,
251            tstats.callsExecuted, tstats.usedFDs);
252     if (!tstats.waitingForPackets) printf("not ");
253     printf("waiting for packets.\n");
254     if (withWaiters)
255       printf("%d calls waiting for a thread\n",tstats.nWaiting);
256     if ( withIdleThreads )
257       printf("%d threads are idle\n", tstats.idleThreads);
258
259     if (rxstats) {
260         if (!withRxStats) {
261   noRxStats:
262             withRxStats = 0;
263             fprintf (stderr, "WARNING: Server doesn't support retrieval of Rx statistics\n");
264         }
265         else {
266             struct rx_stats rxstats;
267
268             /* should gracefully handle the case where rx_stats grows */
269             code = rx_GetServerStats(s, host, port, &rxstats, &supportedStatValues);
270             if (code < 0) {
271                 printf("rxstats call failed with code %d\n", code);
272                 exit(1);
273             }
274             if (code != sizeof(rxstats)) {
275                 if ((((struct rx_debugIn *)(&rxstats))->type ==
276                      RX_DEBUGI_BADTYPE)) goto noRxStats;
277                 printf ("WARNING: returned Rx statistics of unexpected size (got %d)\n",
278                         code);
279                 /* handle other versions?... */
280             }
281
282             rx_PrintTheseStats (stdout, &rxstats, sizeof(rxstats),
283                                 tstats.nFreePackets, tstats.version);
284         }
285     }
286
287     if (!noConns) {
288         if (allconns) {
289             if (!withAllConn) fprintf (stderr, "WARNING: Server doesn't support retrieval of all connections,\n         getting only interesting instead.\n");
290         }
291
292         if (onlyServer) printf ("Showing only server connections\n");
293         if (onlyClient) printf ("Showing only client connections\n");
294         if (onlyAuth != 999) {
295             static char *name[] =
296                 {"unauthenticated", "rxkad_clear", "rxkad_auth", "rxkad_crypt"};
297             printf ("Showing only %s connections\n", name[onlyAuth+1]);
298         }
299         if (onlyHost != -1) {
300             hostAddr.s_addr = onlyHost;
301             printf ("Showing only connections from host %s\n",
302                                     inet_ntoa(hostAddr));
303         }
304         if (onlyPort != -1)
305             printf ("Showing only connections on port %u\n", ntohs(onlyPort));
306
307         for(i=0;;i++) {
308             code = rx_GetServerConnections(s, host, port, &nextconn, allconns,
309                                            supportedDebugValues, &tconn,
310                                            &supportedConnValues);
311             if (code < 0) {
312                 printf("getconn call failed with code %d\n", code);
313                 break;
314             }
315             if (tconn.cid == 0xffffffff) {
316                 printf("Done.\n");
317                 break;
318             }
319
320             /* see if we're in nodally mode and all calls are dallying */
321             if (nodally) {
322                 flag = 0;
323                 for(j=0;j<RX_MAXCALLS;j++) {
324                     if (tconn.callState[j] != RX_STATE_NOTINIT &&
325                         tconn.callState[j] != RX_STATE_DALLY) {
326                         flag = 1;
327                         break;
328                     }
329                 }
330                 if (flag == 0) {
331                     /* this call looks too ordinary, bump skipped count and go
332                      * around again */
333                     dallyCounter++;
334                     continue;
335                 }
336             }
337             if ((onlyHost != -1) && (onlyHost != tconn.host)) continue;
338             if ((onlyPort != -1) && (onlyPort != tconn.port)) continue;
339             if (onlyServer && (tconn.type != RX_SERVER_CONNECTION)) continue;
340             if (onlyClient && (tconn.type != RX_CLIENT_CONNECTION)) continue;
341             if (onlyAuth != 999) {
342                 if (onlyAuth == -1) {
343                     if (tconn.securityIndex != 0) continue;
344                 } else {
345                     if (tconn.securityIndex != 2) continue;
346                     if (withSecStats && (tconn.secStats.type == 3) &&
347                         (tconn.secStats.level != onlyAuth)) continue;
348                 }
349             }
350
351             /* now display the connection */
352             hostAddr.s_addr = tconn.host;
353             printf("Connection from host %s, port %hu, ",
354                    inet_ntoa(hostAddr), ntohs(tconn.port));
355             if (tconn.epoch)
356                 printf ("Cuid %x/%x", tconn.epoch, tconn.cid);
357             else printf ("cid %x", tconn.cid);
358             if (tconn.error) printf (", error %d", tconn.error);
359             printf("\n  serial %d, ", tconn.serial);
360             printf(" natMTU %d, ", tconn.natMTU);
361
362             if (tconn.flags) {
363                 printf ("flags");
364                 if (tconn.flags & RX_CONN_MAKECALL_WAITING)
365                     printf(" MAKECALL_WAITING");
366                 if (tconn.flags & RX_CONN_DESTROY_ME) printf(" DESTROYED");
367                 if (tconn.flags & RX_CONN_USING_PACKET_CKSUM) printf(" pktCksum");
368                 printf (", ");
369             }
370             printf("security index %d, ", tconn.securityIndex);
371             if (tconn.type == RX_CLIENT_CONNECTION) printf("client conn\n");
372             else printf("server conn\n");
373
374             if (withSecStats) {
375                 switch ((int)tconn.secStats.type) {
376                   case 0:
377                     if (tconn.securityIndex == 2)
378                         printf ("  no GetStats procedure for security object\n");
379                     break;
380                   case 1:
381                     printf ("  rxnull level=%d, flags=%d\n",
382                             tconn.secStats.level, tconn.secStats.flags);
383                     break;
384                   case 2:
385                     printf ("  rxvab level=%d, flags=%d\n",
386                             tconn.secStats.level, tconn.secStats.flags);
387                     break;
388                   case 3: {
389                       char *level;
390                       char flags = tconn.secStats.flags;
391                       if (tconn.secStats.level == 0) level = "clear";
392                       else if (tconn.secStats.level == 1) level = "auth";
393                       else if (tconn.secStats.level == 2) level = "crypt";
394                       else level = "unknown";
395                       printf ("  rxkad: level %s", level);
396                       if (flags) printf (", flags");
397                       if (flags & 1) printf (" unalloc");
398                       if (flags & 2) printf (" authenticated");
399                       if (flags & 4) printf (" expired");
400                       if (flags & 8) printf (" pktCksum");
401                       if (tconn.secStats.expires)
402                           /* Apparently due to a bug in the RT compiler that
403                            * prevents (afs_uint32)0xffffffff => (double) from working,
404                            * this code produces negative lifetimes when run on the
405                            * RT. */
406                           printf (", expires in %.1f hours",
407                                   ((afs_uint32)tconn.secStats.expires -
408                                    time(0)) / 3600.0);
409                       if (!(flags & 1)) {
410                           printf ("\n  Received %d bytes in %d packets\n", 
411                                   tconn.secStats.bytesReceived,
412                                   tconn.secStats.packetsReceived);
413                           printf ("  Sent %d bytes in %d packets\n", 
414                                   tconn.secStats.bytesSent,
415                                   tconn.secStats.packetsSent);
416                       } else printf ("\n");
417                       break;
418                   }
419                       
420                   default: printf("  unknown\n");
421                 }
422             }
423
424             for(j=0;j<RX_MAXCALLS;j++) {
425                 printf("    call %d: # %d, state ", j, tconn.callNumber[j]);
426                 if (tconn.callState[j]==RX_STATE_NOTINIT) {
427                     printf("not initialized\n");
428                     continue;
429                 }
430                 else if (tconn.callState[j]==RX_STATE_PRECALL)
431                     printf("precall, ");
432                 else if (tconn.callState[j] == RX_STATE_ACTIVE)
433                     printf("active, ");
434                 else if (tconn.callState[j] == RX_STATE_DALLY)
435                     printf("dally, ");
436                 else if (tconn.callState[j] == RX_STATE_HOLD)
437                     printf("hold, ");
438                 printf("mode: ");
439                 if (tconn.callMode[j]==RX_MODE_SENDING)
440                     printf("sending");
441                 else if (tconn.callMode[j]==RX_MODE_RECEIVING)
442                     printf("receiving");
443                 else if (tconn.callMode[j]==RX_MODE_ERROR)
444                     printf("error");
445                 else if (tconn.callMode[j] == RX_MODE_EOF)
446                     printf("eof");
447                 else printf("unknown");
448                 if (tconn.callFlags[j]) {
449                     printf(", flags:");
450                     if (tconn.callFlags[j]&RX_CALL_READER_WAIT)
451                         printf(" reader_wait");
452                     if (tconn.callFlags[j]&RX_CALL_WAIT_WINDOW_ALLOC)
453                         printf(" window_alloc");
454                     if (tconn.callFlags[j]&RX_CALL_WAIT_WINDOW_SEND)
455                         printf(" window_send");
456                     if (tconn.callFlags[j]&RX_CALL_WAIT_PACKETS)
457                         printf(" wait_packets");
458                     if (tconn.callFlags[j]&RX_CALL_WAIT_PROC)
459                         printf(" waiting_for_process");
460                     if (tconn.callFlags[j]&RX_CALL_RECEIVE_DONE)
461                         printf(" receive_done");
462                     if (tconn.callFlags[j]&RX_CALL_CLEARED)
463                         printf(" call_cleared");
464                 }
465                 if (tconn.callOther[j] & RX_OTHER_IN)
466                     printf(", has_input_packets");
467                 if (tconn.callOther[j] & RX_OTHER_OUT)
468                     printf(", has_output_packets");
469                 printf("\n");
470             }
471         }
472         if (nodally) printf("Skipped %d dallying connections.\n", dallyCounter);
473     }
474     if (showPeers && withPeers) {
475         for(i=0;;i++) {
476             struct rx_debugPeer tpeer;
477             code = rx_GetServerPeers(s, host, port, &nextpeer, allconns, &tpeer, &supportedPeerValues);
478             if (code < 0) {
479                 printf("getpeer call failed with code %d\n", code);
480                 break;
481             }
482             if (tpeer.host == 0xffffffff) {
483                 printf("Done.\n");
484                 break;
485             }
486
487             if ((onlyHost != -1) && (onlyHost != tpeer.host)) continue;
488             if ((onlyPort != -1) && (onlyPort != tpeer.port)) continue;
489
490             /* now display the peer */
491             hostAddr.s_addr = tpeer.host;
492             printf("Peer at host %s, port %hu\n",
493                    inet_ntoa(hostAddr), ntohs(tpeer.port));
494             printf("\tifMTU %hu\tnatMTU %hu\tmaxMTU %hu\n",
495                    tpeer.ifMTU, tpeer.natMTU, tpeer.maxMTU);
496             printf("\tpackets sent %d\tpacket resends %d\n",
497                    tpeer.nSent, tpeer.reSends);
498             printf("\tbytes sent high %d low %d\n",
499                    tpeer.bytesSent.high, tpeer.bytesSent.low);
500             printf("\tbytes received high %d low %d\n",
501                    tpeer.bytesReceived.high, tpeer.bytesReceived.low);
502             printf("\trtt %d msec, rtt_dev %d msec\n",
503                    tpeer.rtt >> 3, tpeer.rtt_dev >> 2);
504             printf("\ttimeout %d.%03d sec\n",
505                    tpeer.timeout.sec, tpeer.timeout.usec / 1000);
506         }
507     }
508     exit(0);
509 }
510
511 /* simple main program */
512 #ifndef AFS_NT40_ENV
513 #include "AFS_component_version_number.c"
514 #endif
515 int main(argc, argv)
516 int argc;
517 char **argv;
518 {
519     struct cmd_syndesc *ts;
520
521 #ifdef AFS_NT40_ENV
522     if (afs_winsockInit()<0) {
523         printf("%s: Couldn't initialize winsock. Exiting...\n", argv[0]);
524         return 1;
525     }
526 #endif
527
528     ts = cmd_CreateSyntax((char *) 0, MainCommand, 0, "probe RX server");
529     cmd_AddParm(ts, "-servers", CMD_SINGLE, CMD_REQUIRED, "server machine");
530     cmd_AddParm(ts, "-port", CMD_SINGLE, CMD_OPTIONAL, "IP port");
531     cmd_AddParm(ts, "-nodally", CMD_FLAG, CMD_OPTIONAL,
532                 "don't show dallying conns");
533     cmd_AddParm(ts, "-allconnections", CMD_FLAG, CMD_OPTIONAL,
534                 "don't filter out uninteresting connections on server");
535     cmd_AddParm(ts, "-rxstats", CMD_FLAG, CMD_OPTIONAL, "show Rx statistics");
536     cmd_AddParm(ts, "-onlyserver", CMD_FLAG, CMD_OPTIONAL,
537                 "only show server conns");
538     cmd_AddParm(ts, "-onlyclient", CMD_FLAG, CMD_OPTIONAL,
539                 "only show client conns");
540     cmd_AddParm(ts, "-onlyport", CMD_SINGLE, CMD_OPTIONAL, "show only <port>");
541     cmd_AddParm(ts, "-onlyhost", CMD_SINGLE, CMD_OPTIONAL, "show only <host>");
542     cmd_AddParm(ts, "-onlyauth", CMD_SINGLE, CMD_OPTIONAL,
543                 "show only <auth level>");
544
545     cmd_AddParm(ts,"-version",CMD_FLAG,CMD_OPTIONAL,"show AFS version id");
546     cmd_AddParm(ts,"-noconns",CMD_FLAG,CMD_OPTIONAL,"show no connections");
547     cmd_AddParm(ts,"-peers",CMD_FLAG,CMD_OPTIONAL,"show peers");
548
549     cmd_Dispatch(argc, argv);
550     exit(0);
551 }