2 ****************************************************************************
3 * Copyright IBM Corporation 1988, 1989 - All Rights Reserved *
5 * Permission to use, copy, modify, and distribute this software and its *
6 * documentation for any purpose and without fee is hereby granted, *
7 * provided that the above copyright notice appear in all copies and *
8 * that both that copyright notice and this permission notice appear in *
9 * supporting documentation, and that the name of IBM not be used in *
10 * advertising or publicity pertaining to distribution of the software *
11 * without specific, written prior permission. *
13 * IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL *
14 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL IBM *
15 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY *
16 * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER *
17 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING *
18 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
19 ****************************************************************************
21 #include <sys/types.h>
23 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
52 PortNumber(char *aport
)
54 uint16_t port
= atoi(aport
);
61 struct servent
*ts
= getservbyname(aname
, NULL
);
64 return ts
->s_port
; /* returns it in network byte order */
68 MakeCall (int asocket
, uint32_t ahost
, uint16_t aport
, char *adata
,
69 long alen
, char *aresult
, long aresultLen
)
71 static long counter
= 100;
73 struct rx_header theader
;
77 struct sockaddr_in taddr
, faddr
;
81 endTime
= time(0) + TIMEOUT
; /* try for N seconds */
83 tp
= &tbuffer
[sizeof(struct rx_header
)];
84 taddr
.sin_family
= AF_INET
;
85 taddr
.sin_port
= aport
;
86 taddr
.sin_addr
.s_addr
= ahost
;
88 memset(&theader
, 0, sizeof(theader
));
89 theader
.epoch
= htonl(999);
91 theader
.callNumber
= htonl(counter
);
94 theader
.type
= RX_PACKET_TYPE_DEBUG
;
95 theader
.flags
= RX_CLIENT_INITIATED
| RX_LAST_PACKET
;
96 theader
.serviceId
= 0;
98 if (sizeof(theader
) + alen
> sizeof(tbuffer
))
99 errx(1, "message to large");
101 memcpy(tbuffer
, &theader
, sizeof(theader
));
102 memcpy(tp
, adata
, alen
);
103 code
= sendto(asocket
, tbuffer
, alen
+sizeof(struct rx_header
), 0,
104 (struct sockaddr
*)&taddr
, sizeof(struct sockaddr_in
));
108 /* see if there's a packet available */
110 if (asocket
>= FD_SETSIZE
) {
111 printf("rxdebug: socket fd too large\n");
116 FD_SET(asocket
,&imask
);
119 code
= select(asocket
+ 1, &imask
, NULL
, NULL
, &tv
);
124 /* now receive a packet */
125 socklen_t faddrLen
= sizeof(struct sockaddr_in
);
127 code
= recvfrom(asocket
, tbuffer
, sizeof(tbuffer
), 0,
128 (struct sockaddr
*)&faddr
, &faddrLen
);
132 memcpy(&theader
, tbuffer
, sizeof(struct rx_header
));
133 if (counter
== ntohl(theader
.callNumber
))
137 /* see if we've timed out */
138 if (endTime
< time(0)) return -1;
140 code
-= sizeof(struct rx_header
);
141 if (code
> aresultLen
) code
= aresultLen
;
142 memcpy(aresult
, tp
, code
);
147 GetVersion(int asocket
, uint32_t ahost
, uint16_t aport
,
148 void *adata
, long alen
,
149 char *aresult
, long aresultLen
)
151 static long counter
= 100;
153 struct rx_header theader
;
157 struct sockaddr_in taddr
, faddr
;
161 endTime
= time(0) + TIMEOUT
; /* try for N seconds */
163 tp
= &tbuffer
[sizeof(struct rx_header
)];
164 taddr
.sin_family
= AF_INET
;
165 taddr
.sin_port
= aport
;
166 taddr
.sin_addr
.s_addr
= ahost
;
168 memset(&theader
, 0, sizeof(theader
));
169 theader
.epoch
= htonl(999);
171 theader
.callNumber
= htonl(counter
);
174 theader
.type
= RX_PACKET_TYPE_VERSION
;
175 theader
.flags
= RX_CLIENT_INITIATED
| RX_LAST_PACKET
;
176 theader
.serviceId
= 0;
178 if (sizeof(theader
) + alen
> sizeof(tbuffer
))
179 errx(1, "message to large");
181 memcpy(tbuffer
, &theader
, sizeof(theader
));
182 memcpy(tp
, adata
, alen
);
184 code
= sendto(asocket
, tbuffer
, alen
+sizeof(struct rx_header
), 0,
185 (struct sockaddr
*)&taddr
, sizeof(struct sockaddr_in
));
190 if (asocket
>= FD_SETSIZE
) {
191 printf("rxdebug: socket fd too large\n");
195 /* see if there's a packet available */
197 FD_SET(asocket
, &imask
);
204 code
= select(asocket
+ 1, &imask
, 0, 0, &tv
);
209 /* now receive a packet */
210 socklen_t faddrLen
= sizeof(struct sockaddr_in
);
212 code
= recvfrom(asocket
, tbuffer
, sizeof(tbuffer
), 0,
213 (struct sockaddr
*)&faddr
, &faddrLen
);
218 memcpy(&theader
, tbuffer
, sizeof(struct rx_header
));
220 if (counter
== ntohl(theader
.callNumber
))
224 /* see if we've timed out */
225 if (endTime
< time(0)) return -1;
227 code
-= sizeof(struct rx_header
);
228 if (code
> aresultLen
)
230 memcpy(aresult
, tp
, code
);
235 MapOldConn (char version
, struct rx_debugConn
*tconn
)
238 struct rx_debugConn_vL
*vL
= (struct rx_debugConn_vL
*)tconn
;
239 #define MOVEvL(a) (tconn->a = vL->a)
241 if ((version
<= RX_DEBUGI_VERSION_W_UNALIGNED_CONN
) ||
242 (version
> RX_DEBUGI_VERSION
)) {
243 /* any old or unrecognized version... */
244 for (i
=0;i
<RX_MAXCALLS
;i
++) {
245 MOVEvL(callState
[i
]);
247 MOVEvL(callFlags
[i
]);
248 MOVEvL(callOther
[i
]);
250 if (version
== RX_DEBUGI_VERSION_W_SECSTATS
) {
251 MOVEvL(secStats
.type
);
252 MOVEvL(secStats
.level
);
253 MOVEvL(secStats
.flags
);
254 MOVEvL(secStats
.expires
);
255 MOVEvL(secStats
.packetsReceived
);
256 MOVEvL(secStats
.packetsSent
);
257 MOVEvL(secStats
.bytesReceived
);
258 MOVEvL(secStats
.bytesSent
);
264 static int nodally_flag
;
265 static int allconns_flag
;
266 static int rxstats_flag
;
267 static int onlyServer_flag
;
268 static int onlyClient_flag
;
269 static int version_flag
;
270 static int noConns_flag
;
271 static int help_flag
;
272 static char *hostName
;
273 static char *portName
;
274 static char *onlyAuthName
;
275 static char *onlyPortName
;
276 static char *onlyHostName
;
284 struct sockaddr_in taddr
;
286 struct in_addr hostAddr
;
288 struct rx_debugIn tin
;
299 struct rx_debugStats tstats
;
300 struct rx_debugConn tconn
;
307 char *name
= onlyPortName
;
308 if ((onlyPort
= PortNumber(name
)) == 0)
309 onlyPort
= PortName(name
);
311 printf("rxdebug: can't resolve port name %s\n", name
);
318 char *name
= onlyHostName
;
321 th
= gethostbyname(name
);
323 printf("rxdebug: host %s not found in host table\n", name
);
326 memcpy(&onlyHost
, th
->h_addr
, sizeof(onlyHost
));
328 onlyHost
= 0xffffffff;
331 char *name
= onlyAuthName
;
332 if (strcmp (name
, "clear") == 0) onlyAuth
= 0;
333 else if (strcmp (name
, "auth") == 0) onlyAuth
= 1;
334 else if (strcmp (name
, "crypt") == 0) onlyAuth
= 2;
335 else if ((strcmp (name
, "null") == 0) ||
336 (strcmp (name
, "none") == 0) ||
337 (strncmp (name
, "noauth", 6) == 0) ||
338 (strncmp (name
, "unauth", 6) == 0)) onlyAuth
= -1;
340 fprintf (stderr
, "Unknown authentication level: %s\n", name
);
343 } else onlyAuth
= 999;
349 th
= gethostbyname(hostName
);
351 printf("rxdebug: host %s not found in host table\n", hostName
);
354 memcpy(&host
, th
->h_addr
, sizeof(host
));
356 else host
= htonl(0x7f000001); /* IP localhost */
359 port
= htons(7000); /* default is fileserver */
361 if ((port
= PortNumber(portName
)) == 0)
362 port
= PortName(portName
);
364 printf("rxdebug: can't resolve port name %s\n", portName
);
371 hostAddr
.s_addr
= host
;
372 printf("Trying %s (port %d):\n", inet_ntoa(hostAddr
), ntohs(port
));
373 s
= socket(AF_INET
, SOCK_DGRAM
, 0);
375 memset(&taddr
, 0, sizeof(taddr
));
376 taddr
.sin_family
= AF_INET
;
378 taddr
.sin_addr
.s_addr
= 0;
380 code
= bind(s
, (struct sockaddr
*)&taddr
, sizeof(struct sockaddr_in
));
390 code
= GetVersion(s
, host
, port
, nada
, length
,
394 printf("get version call failed with code %d, errno %d\n",
398 printf("AFS version: %s\n",version
);fflush(stdout
);
405 tin
.type
= htonl(RX_DEBUGI_GETSTATS
);
407 code
= MakeCall(s
, host
, port
, (char *) &tin
, sizeof(tin
),
408 (char *) &tstats
, sizeof(tstats
));
410 printf("getstats call failed with code %d\n", code
);
414 withSecStats
= (tstats
.version
>= RX_DEBUGI_VERSION_W_SECSTATS
);
415 withAllConn
= (tstats
.version
>= RX_DEBUGI_VERSION_W_GETALLCONN
);
416 withRxStats
= (tstats
.version
>= RX_DEBUGI_VERSION_W_RXSTATS
);
417 withWaiters
= (tstats
.version
>= RX_DEBUGI_VERSION_W_WAITERS
);
419 printf("Free packets: %ld, packet reclaims: %ld, calls: %ld, "
421 (long)ntohl(tstats
.nFreePackets
),
422 (long)ntohl(tstats
.packetReclaims
),
423 (long)ntohl(tstats
.callsExecuted
),
425 if (!tstats
.waitingForPackets
) printf("not ");
426 printf("waiting for packets.\n");
428 printf("%ld calls waiting for a thread\n",
429 (long)ntohl(tstats
.nWaiting
));
431 if (rxstats_flag
&& withRxStats
) {
433 fprintf (stderr
, "WARNING: Server doens't support "
434 "retrieval of Rx statistics\n");
436 struct rx_stats rxstats
;
439 memset (&rxstats
, 0, sizeof(rxstats
));
440 tin
.type
= htonl(RX_DEBUGI_RXSTATS
);
442 /* should gracefully handle the case where rx_stats grows */
443 code
= MakeCall(s
, host
, port
, (char *) &tin
, sizeof(tin
),
444 (char *) &rxstats
, sizeof(rxstats
));
446 printf("rxstats call failed with code %d\n", code
);
450 if ((code
== sizeof(tin
)) &&
451 (ntohl(((struct rx_debugIn
*)(void*)&rxstats
)->type
) ==
452 RX_DEBUGI_BADTYPE
)) {
453 fprintf (stderr
, "WARNING: Server doens't support "
454 "retrieval of Rx statistics\n");
456 if (code
!= sizeof(rxstats
)) {
457 /* handle other versions?... */
458 fprintf (stderr
, "WARNING: returned Rx statistics of "
459 "unexpected size (got %d)\n",
462 /* Since its all int32's, convert to host order with a loop. */
463 lp
= (uint32_t*)&rxstats
;
464 for (i
=0; i
< sizeof(rxstats
)/sizeof(uint32_t); i
++)
465 lp
[i
] = ntohl(lp
[i
]);
467 rx_PrintTheseStats (stdout
, &rxstats
, sizeof(rxstats
));
475 tin
.type
= htonl(RX_DEBUGI_GETCONN
);
477 tin
.type
= htonl(RX_DEBUGI_GETALLCONN
);
479 if (onlyServer_flag
) printf ("Showing only server connections\n");
480 if (onlyClient_flag
) printf ("Showing only client connections\n");
481 if (onlyAuth
!= 999) {
482 static char *name
[] =
483 {"unauthenticated", "rxkad_clear", "rxkad_auth", "rxkad_crypt"};
484 printf ("Showing only %s connections\n", name
[onlyAuth
+1]);
486 if (onlyHost
!= 0xffffffff) {
487 hostAddr
.s_addr
= onlyHost
;
488 printf ("Showing only connections from host %s\n",
489 inet_ntoa(hostAddr
));
491 if (onlyPort
!= 0xffff)
492 printf ("Showing only connections on port %u\n", ntohs(onlyPort
));
495 tin
.index
= htonl(i
);
496 memset (&tconn
, 0, sizeof(tconn
));
497 code
= MakeCall(s
, host
, port
, (char *)&tin
, sizeof(tin
),
498 (char *) &tconn
, sizeof(tconn
));
500 printf("getconn call failed with code %d\n", code
);
503 MapOldConn (tstats
.version
, &tconn
);
504 if (tconn
.cid
== htonl(0xffffffff)) {
509 /* see if we're in nodally mode and all calls are dallying */
512 for(j
=0;j
<RX_MAXCALLS
;j
++) {
513 if (tconn
.callState
[j
] != RX_STATE_NOTINIT
&&
514 tconn
.callState
[j
] != RX_STATE_DALLY
) {
521 * this call looks too ordinary, bump skipped count and go
528 if ((onlyHost
!= -1) && (onlyHost
!= tconn
.host
)) continue;
529 if ((onlyPort
!= 0) && (onlyPort
!= tconn
.port
)) continue;
530 if (onlyServer_flag
&& (tconn
.type
!= RX_SERVER_CONNECTION
)) continue;
531 if (onlyClient_flag
&& (tconn
.type
!= RX_CLIENT_CONNECTION
)) continue;
532 if (onlyAuth
!= 999) {
533 if (onlyAuth
== -1) {
534 if (tconn
.securityIndex
!= 0) continue;
536 if (tconn
.securityIndex
!= 2) continue;
537 if (withSecStats
&& (tconn
.secStats
.type
== 3) &&
538 (tconn
.secStats
.level
!= onlyAuth
)) continue;
542 /* now display the connection */
543 hostAddr
.s_addr
= tconn
.host
;
544 printf("Connection from host %s, port %d, ",
545 inet_ntoa(hostAddr
), ntohs(tconn
.port
));
547 printf ("Cuid %lx/%lx", (unsigned long)ntohl(tconn
.epoch
),
548 (unsigned long)ntohl(tconn
.cid
));
550 printf ("cid %lx", (unsigned long)ntohl(tconn
.cid
));
552 printf (", error %ld", (long)ntohl(tconn
.error
));
553 printf("\n serial %ld, ", (long)ntohl(tconn
.serial
));
554 printf(" maxPacketSize %ld, ", (long)ntohl(tconn
.maxPacketSize
));
558 if (tconn
.flags
& RX_CONN_MAKECALL_WAITING
)
559 printf(" MAKECALL_WAITING");
560 if (tconn
.flags
& RX_CONN_DESTROY_ME
) printf(" DESTROYED");
561 if (tconn
.flags
& RX_CONN_USING_PACKET_CKSUM
) printf(" pktCksum");
564 printf("security index %d, ", tconn
.securityIndex
);
565 if (tconn
.type
== RX_CLIENT_CONNECTION
) printf("client conn\n");
566 else printf("server conn\n");
569 switch ((int)tconn
.secStats
.type
) {
571 if (tconn
.securityIndex
== 2)
572 printf (" no GetStats procedure for security object\n");
575 printf (" rxnull level=%d, flags=%d\n",
576 tconn
.secStats
.level
, (int)tconn
.secStats
.flags
);
579 printf (" rxvab level=%d, flags=%d\n",
580 tconn
.secStats
.level
, (int)tconn
.secStats
.flags
);
584 char flags
= ntohl(tconn
.secStats
.flags
);
585 if (tconn
.secStats
.level
== 0) level
= "clear";
586 else if (tconn
.secStats
.level
== 1) level
= "auth";
587 else if (tconn
.secStats
.level
== 2) level
= "crypt";
588 else level
= "unknown";
589 printf (" rxkad: level %s", level
);
590 if (flags
) printf (", flags");
591 if (flags
& 1) printf (" unalloc");
592 if (flags
& 2) printf (" authenticated");
593 if (flags
& 4) printf (" expired");
594 if (flags
& 8) printf (" pktCksum");
595 if (tconn
.secStats
.expires
)
596 /* Apparently due to a bug in the RT compiler that
597 * prevents (u_long)0xffffffff => (double) from working,
598 * this code produces negative lifetimes when run on the
600 printf (", expires in %.1f hours",
601 ((u_long
)ntohl(tconn
.secStats
.expires
) -
604 printf ("\n Received %lu bytes in %lu packets\n",
605 (long)ntohl(tconn
.secStats
.bytesReceived
),
606 (long)ntohl(tconn
.secStats
.packetsReceived
));
607 printf (" Sent %lu bytes in %lu packets\n",
608 (long)ntohl(tconn
.secStats
.bytesSent
),
609 (long)ntohl(tconn
.secStats
.packetsSent
));
615 default: printf(" unknown\n");
619 for(j
=0;j
<RX_MAXCALLS
;j
++) {
620 printf(" call %d: # %ld, state ", j
,
621 (long)ntohl(tconn
.callNumber
[j
]));
622 if (tconn
.callState
[j
]==RX_STATE_NOTINIT
) {
623 printf("not initialized\n");
626 else if (tconn
.callState
[j
]==RX_STATE_PRECALL
)
628 else if (tconn
.callState
[j
] == RX_STATE_ACTIVE
)
630 else if (tconn
.callState
[j
] == RX_STATE_DALLY
)
633 if (tconn
.callMode
[j
]==RX_MODE_SENDING
)
635 else if (tconn
.callMode
[j
]==RX_MODE_RECEIVING
)
637 else if (tconn
.callMode
[j
]==RX_MODE_ERROR
)
639 else if (tconn
.callMode
[j
] == RX_MODE_EOF
)
641 else printf("unknown");
642 if (tconn
.callFlags
[j
]) {
644 if (tconn
.callFlags
[j
]&RX_CALL_READER_WAIT
)
645 printf(" reader_wait");
646 if (tconn
.callFlags
[j
]&RX_CALL_WAIT_WINDOW_ALLOC
)
647 printf(" window_alloc");
648 if (tconn
.callFlags
[j
]&RX_CALL_WAIT_WINDOW_SEND
)
649 printf(" window_send");
650 if (tconn
.callFlags
[j
]&RX_CALL_WAIT_PACKETS
)
651 printf(" wait_packets");
652 if (tconn
.callFlags
[j
]&RX_CALL_WAIT_PROC
)
653 printf(" waiting_for_process");
654 if (tconn
.callFlags
[j
]&RX_CALL_RECEIVE_DONE
)
655 printf(" receive_done");
656 if (tconn
.callFlags
[j
]&RX_CALL_CLEARED
)
657 printf(" call_cleared");
659 if (tconn
.callOther
[j
] & RX_OTHER_IN
)
660 printf(", has_input_packets");
661 if (tconn
.callOther
[j
] & RX_OTHER_OUT
)
662 printf(", has_output_packets");
667 printf("Skipped %d dallying connections.\n", dallyCounter
);
671 static struct agetargs args
[] = {
672 {"servers", 0, aarg_string
, &hostName
,
673 "server machine", NULL
, aarg_mandatory
},
674 {"port", 0, aarg_string
, &portName
,
675 "IP port", NULL
, aarg_optional_swless
},
676 {"nodally", 0, aarg_flag
, &nodally_flag
,
677 "don't show dallying conns", NULL
},
678 {"allconnections", 0, aarg_flag
, &allconns_flag
,
679 "don't filter out uninteresting connections on server"},
680 {"rxstats", 0, aarg_flag
, &rxstats_flag
,
681 "show Rx statistics", NULL
},
682 {"onlyserver", 0, aarg_flag
, &onlyServer_flag
,
683 "only show server conns", NULL
},
684 {"onlyclient", 0, aarg_flag
, &onlyClient_flag
,
685 "only show client conns", NULL
},
686 {"onlyport", 0, aarg_integer
, &onlyPortName
,
687 "show only <port>", NULL
},
688 {"onlyhost", 0, aarg_string
, &onlyHostName
,
689 "show only <host>", NULL
},
690 {"onlyauth", 0, aarg_string
, &onlyAuthName
,
691 "show only <auth level>", NULL
},
692 {"version", 0, aarg_flag
, &version_flag
,
693 "show AFS version id", NULL
},
694 {"noconns", 0, aarg_flag
, &noConns_flag
,
695 "show no connections", NULL
},
696 {"help", 0, aarg_flag
, &help_flag
,
704 aarg_printusage (args
, "rxdebug", "", AARG_AFSSTYLE
);
708 /* simple main program */
711 main(int argc
, char **argv
)
716 if (agetarg (args
, argc
, argv
, &o
, AARG_AFSSTYLE
)) {
730 fprintf (stderr
, "create volume: unparsed arguments\n");
734 return MainCommand();