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