2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afsconfig.h>
11 #include <afs/param.h>
16 #include <afs/afsutil.h>
19 #include <rx/rx_user.h>
20 #include <rx/rx_clock.h>
21 #include <rx/rx_queue.h>
23 #include <rx/rx_globals.h>
29 PortNumber(char *aport
)
35 while ((tc
= *aport
++)) {
36 if (tc
< '0' || tc
> '9')
37 return -1; /* bad port number */
39 total
+= tc
- (int)'0';
48 ts
= getservbyname(aname
, NULL
);
51 return ts
->s_port
; /* returns it in network byte order */
55 MainCommand(struct cmd_syndesc
*as
, void *arock
)
60 struct sockaddr_in taddr
;
62 struct in_addr hostAddr
;
69 int onlyClient
, onlyServer
;
83 struct rx_debugStats tstats
;
84 char *portName
, *hostName
;
86 struct rx_debugConn tconn
;
92 afs_int32 length
= 64;
94 afs_uint32 supportedDebugValues
= 0;
95 afs_uint32 supportedStatValues
= 0;
96 afs_uint32 supportedConnValues
= 0;
97 afs_uint32 supportedPeerValues
= 0;
98 afs_int32 nextconn
= 0;
99 afs_int32 nextpeer
= 0;
101 nodally
= (as
->parms
[2].items
? 1 : 0);
102 allconns
= (as
->parms
[3].items
? 1 : 0);
103 rxstats
= (as
->parms
[4].items
? 1 : 0);
104 onlyServer
= (as
->parms
[5].items
? 1 : 0);
105 onlyClient
= (as
->parms
[6].items
? 1 : 0);
106 version_flag
= (as
->parms
[10].items
? 1 : 0);
107 noConns
= (as
->parms
[11].items
? 1 : 0);
108 showPeers
= (as
->parms
[12].items
? 1 : 0);
109 showLong
= (as
->parms
[13].items
? 1 : 0);
111 if (as
->parms
[0].items
)
112 hostName
= as
->parms
[0].items
->data
;
116 if (as
->parms
[1].items
)
117 portName
= as
->parms
[1].items
->data
;
121 if (as
->parms
[7].items
) {
122 char *name
= as
->parms
[7].items
->data
;
123 if ((onlyPort
= PortNumber(name
)) == -1)
124 onlyPort
= PortName(name
);
125 if (onlyPort
== -1) {
126 printf("rxdebug: can't resolve port name %s\n", name
);
132 if (as
->parms
[8].items
) {
133 char *name
= as
->parms
[8].items
->data
;
135 th
= hostutil_GetHostByName(name
);
137 printf("rxdebug: host %s not found in host table\n", name
);
140 memcpy(&onlyHost
, th
->h_addr
, sizeof(afs_int32
));
144 if (as
->parms
[9].items
) {
145 char *name
= as
->parms
[9].items
->data
;
146 if (strcmp(name
, "clear") == 0)
148 else if (strcmp(name
, "auth") == 0)
150 else if (strcmp(name
, "crypt") == 0)
152 else if ((strcmp(name
, "null") == 0) || (strcmp(name
, "none") == 0)
153 || (strncmp(name
, "noauth", 6) == 0)
154 || (strncmp(name
, "unauth", 6) == 0))
157 fprintf(stderr
, "Unknown authentication level: %s\n", name
);
165 th
= hostutil_GetHostByName(hostName
);
167 printf("rxdebug: host %s not found in host table\n", hostName
);
170 memcpy(&host
, th
->h_addr
, sizeof(afs_int32
));
172 host
= htonl(0x7f000001); /* IP localhost */
175 port
= htons(7000); /* default is fileserver */
177 if ((port
= PortNumber(portName
)) == -1)
178 port
= PortName(portName
);
180 printf("rxdebug: can't resolve port name %s\n", portName
);
187 hostAddr
.s_addr
= host
;
188 afs_inet_ntoa_r(hostAddr
.s_addr
, hoststr
);
189 printf("Trying %s (port %d):\n", hoststr
, ntohs(port
));
190 s
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
191 if (s
== OSI_NULLSOCKET
) {
193 fprintf(stderr
, "socket() failed with error %u\n", WSAGetLastError());
199 taddr
.sin_family
= AF_INET
;
201 taddr
.sin_addr
.s_addr
= 0;
202 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
203 taddr
.sin_len
= sizeof(struct sockaddr_in
);
205 code
= bind(s
, (struct sockaddr
*)&taddr
, sizeof(struct sockaddr_in
));
208 fprintf(stderr
, "bind() failed with error %u\n", WSAGetLastError());
216 memset(version
, 0, sizeof(version
));
218 code
= rx_GetServerVersion(s
, host
, port
, length
, version
);
220 printf("get version call failed with code %d, errno %d\n", code
,
224 version
[sizeof(version
) - 1] = '\0';
225 printf("AFS version: %s\n", version
);
233 code
= rx_GetServerDebug(s
, host
, port
, &tstats
, &supportedDebugValues
);
235 printf("getstats call failed with code %d\n", code
);
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 withWaited
= (supportedDebugValues
& RX_SERVER_DEBUG_WAITED_CNT
);
245 withPeers
= (supportedDebugValues
& RX_SERVER_DEBUG_ALL_PEER
);
246 withPackets
= (supportedDebugValues
& RX_SERVER_DEBUG_PACKETS_CNT
);
249 printf("Free packets: %d/%d, packet reclaims: %d, calls: %d, used FDs: %d\n",
250 tstats
.nFreePackets
, tstats
.nPackets
, tstats
.packetReclaims
,
251 tstats
.callsExecuted
, tstats
.usedFDs
);
253 printf("Free packets: %d, packet reclaims: %d, calls: %d, used FDs: %d\n",
254 tstats
.nFreePackets
, tstats
.packetReclaims
, tstats
.callsExecuted
,
256 if (!tstats
.waitingForPackets
)
258 printf("waiting for packets.\n");
260 printf("%d calls waiting for a thread\n", tstats
.nWaiting
);
262 printf("%d threads are idle\n", tstats
.idleThreads
);
264 printf("%d calls have waited for a thread\n", tstats
.nWaited
);
271 "WARNING: Server doesn't support retrieval of Rx statistics\n");
273 struct rx_statistics rxstats
;
275 /* should gracefully handle the case where rx_stats grows */
277 rx_GetServerStats(s
, host
, port
, &rxstats
,
278 &supportedStatValues
);
280 printf("rxstats call failed with code %d\n", code
);
283 if (code
!= sizeof(rxstats
)) {
284 struct rx_debugIn debug
;
285 memcpy(&debug
, &rxstats
, sizeof(debug
));
286 if (debug
.type
== RX_DEBUGI_BADTYPE
)
289 ("WARNING: returned Rx statistics of unexpected size (got %d)\n",
291 /* handle other versions?... */
294 rx_PrintTheseStats(stdout
, &rxstats
, sizeof(rxstats
),
295 tstats
.nFreePackets
, tstats
.version
);
303 "WARNING: Server doesn't support retrieval of all connections,\n getting only interesting instead.\n");
307 printf("Showing only server connections\n");
309 printf("Showing only client connections\n");
310 if (onlyAuth
!= 999) {
311 static char *name
[] =
312 { "unauthenticated", "rxkad_clear", "rxkad_auth",
315 printf("Showing only %s connections\n", name
[onlyAuth
+ 1]);
317 if (onlyHost
!= -1) {
318 hostAddr
.s_addr
= onlyHost
;
319 afs_inet_ntoa_r(hostAddr
.s_addr
, hoststr
);
320 printf("Showing only connections from host %s\n",
324 printf("Showing only connections on port %u\n", ntohs(onlyPort
));
328 rx_GetServerConnections(s
, host
, port
, &nextconn
, allconns
,
329 supportedDebugValues
, &tconn
,
330 &supportedConnValues
);
332 printf("getconn call failed with code %d\n", code
);
335 if (tconn
.cid
== (afs_int32
) 0xffffffff) {
340 /* see if we're in nodally mode and all calls are dallying */
343 for (j
= 0; j
< RX_MAXCALLS
; j
++) {
344 if (tconn
.callState
[j
] != RX_STATE_NOTINIT
345 && tconn
.callState
[j
] != RX_STATE_DALLY
) {
351 /* this call looks too ordinary, bump skipped count and go
357 if ((onlyHost
!= -1) && (onlyHost
!= tconn
.host
))
359 if ((onlyPort
!= -1) && (onlyPort
!= tconn
.port
))
361 if (onlyServer
&& (tconn
.type
!= RX_SERVER_CONNECTION
))
363 if (onlyClient
&& (tconn
.type
!= RX_CLIENT_CONNECTION
))
365 if (onlyAuth
!= 999) {
366 if (onlyAuth
== -1) {
367 if (tconn
.securityIndex
!= RX_SECIDX_NULL
)
370 if (tconn
.securityIndex
!= RX_SECIDX_KAD
)
372 if (withSecStats
&& (tconn
.secStats
.type
== RX_SECTYPE_KAD
)
373 && (tconn
.secStats
.level
!= onlyAuth
))
378 /* now display the connection */
379 hostAddr
.s_addr
= tconn
.host
;
380 afs_inet_ntoa_r(hostAddr
.s_addr
, hoststr
);
381 printf("Connection from host %s, port %hu, ", hoststr
,
384 printf("Cuid %x/%x", tconn
.epoch
, tconn
.cid
);
386 printf("cid %x", tconn
.cid
);
388 printf(", error %d", tconn
.error
);
389 printf("\n serial %d, ", tconn
.serial
);
390 printf(" natMTU %d, ", tconn
.natMTU
);
394 if (tconn
.flags
& RX_CONN_MAKECALL_WAITING
)
395 printf(" MAKECALL_WAITING");
396 if (tconn
.flags
& RX_CONN_DESTROY_ME
)
397 printf(" DESTROYED");
398 if (tconn
.flags
& RX_CONN_USING_PACKET_CKSUM
)
400 if (tconn
.flags
& RX_CONN_KNOW_WINDOW
)
401 printf(" knowWindow");
402 if (tconn
.flags
& RX_CONN_RESET
)
404 if (tconn
.flags
& RX_CONN_BUSY
)
406 if (tconn
.flags
& RX_CONN_ATTACHWAIT
)
407 printf(" attachWait");
410 printf("security index %d, ", tconn
.securityIndex
);
411 if (tconn
.type
== RX_CLIENT_CONNECTION
)
412 printf("client conn\n");
414 printf("server conn\n");
417 switch ((int)tconn
.secStats
.type
) {
419 if (tconn
.securityIndex
== RX_SECIDX_KAD
)
421 (" no GetStats procedure for security object\n");
423 case RX_SECTYPE_NULL
:
424 printf(" rxnull level=%d, flags=%d\n",
425 tconn
.secStats
.level
, tconn
.secStats
.flags
);
428 printf(" rxvab level=%d, flags=%d\n",
429 tconn
.secStats
.level
, tconn
.secStats
.flags
);
431 case RX_SECTYPE_KAD
:{
433 char flags
= tconn
.secStats
.flags
;
434 if (tconn
.secStats
.level
== 0)
436 else if (tconn
.secStats
.level
== 1)
438 else if (tconn
.secStats
.level
== 2)
442 printf(" rxkad: level %s", level
);
448 printf(" authenticated");
453 if (tconn
.secStats
.expires
)
454 /* Apparently due to a bug in the RT compiler that
455 * prevents (afs_uint32)0xffffffff => (double) from working,
456 * this code produces negative lifetimes when run on the
458 printf(", expires in %.1f hours",
459 ((afs_uint32
) tconn
.secStats
.expires
-
462 printf("\n Received %u bytes in %u packets\n",
463 tconn
.secStats
.bytesReceived
,
464 tconn
.secStats
.packetsReceived
);
465 printf(" Sent %u bytes in %u packets\n",
466 tconn
.secStats
.bytesSent
,
467 tconn
.secStats
.packetsSent
);
474 printf(" unknown\n");
478 for (j
= 0; j
< RX_MAXCALLS
; j
++) {
479 printf(" call %d: # %d, state ", j
, tconn
.callNumber
[j
]);
480 if (tconn
.callState
[j
] == RX_STATE_NOTINIT
) {
481 printf("not initialized\n");
483 } else if (tconn
.callState
[j
] == RX_STATE_PRECALL
)
485 else if (tconn
.callState
[j
] == RX_STATE_ACTIVE
)
487 else if (tconn
.callState
[j
] == RX_STATE_DALLY
)
489 else if (tconn
.callState
[j
] == RX_STATE_HOLD
)
491 else if (tconn
.callState
[j
] == RX_STATE_RESET
)
494 if (tconn
.callMode
[j
] == RX_MODE_SENDING
)
496 else if (tconn
.callMode
[j
] == RX_MODE_RECEIVING
)
498 else if (tconn
.callMode
[j
] == RX_MODE_ERROR
)
500 else if (tconn
.callMode
[j
] == RX_MODE_EOF
)
504 if (tconn
.callFlags
[j
]) {
506 if (tconn
.callFlags
[j
] & RX_CALL_READER_WAIT
)
507 printf(" reader_wait");
508 if (tconn
.callFlags
[j
] & RX_CALL_WAIT_WINDOW_ALLOC
)
509 printf(" window_alloc");
510 if (tconn
.callFlags
[j
] & RX_CALL_WAIT_WINDOW_SEND
)
511 printf(" window_send");
512 if (tconn
.callFlags
[j
] & RX_CALL_WAIT_PACKETS
)
513 printf(" wait_packets");
514 if (tconn
.callFlags
[j
] & RX_CALL_WAIT_PROC
)
515 printf(" waiting_for_process");
516 if (tconn
.callFlags
[j
] & RX_CALL_RECEIVE_DONE
)
517 printf(" receive_done");
518 if (tconn
.callFlags
[j
] & RX_CALL_CLEARED
)
519 printf(" call_cleared");
521 if (tconn
.callOther
[j
] & RX_OTHER_IN
)
522 printf(", has_input_packets");
523 if (tconn
.callOther
[j
] & RX_OTHER_OUT
)
524 printf(", has_output_packets");
529 printf("Skipped %d dallying connections.\n", dallyCounter
);
531 if (showPeers
&& withPeers
) {
533 struct rx_debugPeer tpeer
;
535 rx_GetServerPeers(s
, host
, port
, &nextpeer
, allconns
, &tpeer
,
536 &supportedPeerValues
);
538 printf("getpeer call failed with code %d\n", code
);
541 if (tpeer
.host
== 0xffffffff) {
546 if ((onlyHost
!= -1) && (onlyHost
!= tpeer
.host
))
548 if ((onlyPort
!= -1) && (onlyPort
!= tpeer
.port
))
551 /* now display the peer */
552 hostAddr
.s_addr
= tpeer
.host
;
553 afs_inet_ntoa_r(hostAddr
.s_addr
, hoststr
);
554 printf("Peer at host %s, port %hu\n", hoststr
,
556 printf("\tifMTU %hu\tnatMTU %hu\tmaxMTU %hu\n", tpeer
.ifMTU
,
557 tpeer
.natMTU
, tpeer
.maxMTU
);
558 printf("\tpackets sent %u\tpacket resends %u\n", tpeer
.nSent
,
560 printf("\tbytes sent high %u low %u\n", tpeer
.bytesSent
.high
,
561 tpeer
.bytesSent
.low
);
562 printf("\tbytes received high %u low %u\n",
563 tpeer
.bytesReceived
.high
, tpeer
.bytesReceived
.low
);
564 printf("\trtt %u msec, rtt_dev %u msec\n", tpeer
.rtt
>> 3,
566 printf("\ttimeout %u.%03u sec\n", tpeer
.timeout
.sec
,
567 tpeer
.timeout
.usec
/ 1000);
571 printf("\tin/out packet skew: %d/%d\n", tpeer
.inPacketSkew
,
572 tpeer
.outPacketSkew
);
573 printf("\tcongestion window %d, MTU %d\n", tpeer
.cwind
,
575 printf("\tcurrent/if/max jumbogram size: %d/%d/%d\n",
576 tpeer
.nDgramPackets
, tpeer
.ifDgramPackets
,
577 tpeer
.maxDgramPackets
);
583 /* simple main program */
585 #include "AFS_component_version_number.c"
588 main(int argc
, char **argv
)
590 struct cmd_syndesc
*ts
;
596 if (afs_winsockInit() < 0) {
597 printf("%s: Couldn't initialize winsock. Exiting...\n", argv
[0]);
602 ts
= cmd_CreateSyntax(NULL
, MainCommand
, NULL
, 0, "probe RX server");
603 cmd_AddParm(ts
, "-servers", CMD_SINGLE
, CMD_REQUIRED
, "server machine");
604 cmd_AddParm(ts
, "-port", CMD_SINGLE
, CMD_OPTIONAL
, "IP port");
605 cmd_AddParm(ts
, "-nodally", CMD_FLAG
, CMD_OPTIONAL
,
606 "don't show dallying conns");
607 cmd_AddParm(ts
, "-allconnections", CMD_FLAG
, CMD_OPTIONAL
,
608 "don't filter out uninteresting connections on server");
609 cmd_AddParm(ts
, "-rxstats", CMD_FLAG
, CMD_OPTIONAL
, "show Rx statistics");
610 cmd_AddParm(ts
, "-onlyserver", CMD_FLAG
, CMD_OPTIONAL
,
611 "only show server conns");
612 cmd_AddParm(ts
, "-onlyclient", CMD_FLAG
, CMD_OPTIONAL
,
613 "only show client conns");
614 cmd_AddParm(ts
, "-onlyport", CMD_SINGLE
, CMD_OPTIONAL
,
616 cmd_AddParm(ts
, "-onlyhost", CMD_SINGLE
, CMD_OPTIONAL
,
618 cmd_AddParm(ts
, "-onlyauth", CMD_SINGLE
, CMD_OPTIONAL
,
619 "show only <auth level>");
621 cmd_AddParm(ts
, "-version", CMD_FLAG
, CMD_OPTIONAL
,
622 "show AFS version id");
623 cmd_AddParm(ts
, "-noconns", CMD_FLAG
, CMD_OPTIONAL
,
624 "show no connections");
625 cmd_AddParm(ts
, "-peers", CMD_FLAG
, CMD_OPTIONAL
, "show peers");
626 cmd_AddParm(ts
, "-long", CMD_FLAG
, CMD_OPTIONAL
, "detailed output");
628 cmd_Dispatch(argc
, argv
);