/* **************************************************************************** * Copyright IBM Corporation 1988, 1989 - All Rights Reserved * * * * Permission to use, copy, modify, and distribute this software and its * * documentation for any purpose and without fee is hereby granted, * * provided that the above copyright notice appear in all copies and * * that both that copyright notice and this permission notice appear in * * supporting documentation, and that the name of IBM not be used in * * advertising or publicity pertaining to distribution of the software * * without specific, written prior permission. * * * * IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL IBM * * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY * * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER * * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * **************************************************************************** */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "rx_user.h" #include "rx_clock.h" #include "rx_queue.h" #include "rx.h" #include "config.h" #include "roken.h" RCSID ("$arla: rxdebug.c,v 1.15 2003/01/19 08:50:12 lha Exp $"); #define TIMEOUT 20 static uint16_t PortNumber(char *aport) { uint16_t port = atoi(aport); return htons(port); } static uint16_t PortName(char *aname) { struct servent *ts = getservbyname(aname, NULL); if (ts == NULL) return 0; return ts->s_port; /* returns it in network byte order */ } static int MakeCall (int asocket, uint32_t ahost, uint16_t aport, char *adata, long alen, char *aresult, long aresultLen) { static long counter = 100; long endTime; struct rx_header theader; char tbuffer[1500]; int code; struct timeval tv; struct sockaddr_in taddr, faddr; int faddrLen; fd_set imask; char *tp; endTime = time(0) + TIMEOUT; /* try for N seconds */ counter++; tp = &tbuffer[sizeof(struct rx_header)]; taddr.sin_family = AF_INET; taddr.sin_port = aport; taddr.sin_addr.s_addr = ahost; while(1) { memset(&theader, 0, sizeof(theader)); theader.epoch = htonl(999); theader.cid = 0; theader.callNumber = htonl(counter); theader.seq = 0; theader.serial = 0; theader.type = RX_PACKET_TYPE_DEBUG; theader.flags = RX_CLIENT_INITIATED | RX_LAST_PACKET; theader.serviceId = 0; if (sizeof(theader) + alen > sizeof(tbuffer)) errx(1, "message to large"); memcpy(tbuffer, &theader, sizeof(theader)); memcpy(tp, adata, alen); code = sendto(asocket, tbuffer, alen+sizeof(struct rx_header), 0, (struct sockaddr *)&taddr, sizeof(struct sockaddr_in)); if (code == -1) { err(1, "sendto"); } /* see if there's a packet available */ if (asocket >= FD_SETSIZE) { printf("rxdebug: socket fd too large\n"); exit (1); } FD_ZERO(&imask); FD_SET(asocket,&imask); tv.tv_sec = 1; tv.tv_usec = 0; code = select(asocket + 1, &imask, NULL, NULL, &tv); if (code == -1) { err(1, "select"); } if (code > 0) { /* now receive a packet */ faddrLen = sizeof(struct sockaddr_in); code = recvfrom(asocket, tbuffer, sizeof(tbuffer), 0, (struct sockaddr *)&faddr, &faddrLen); if (code == -1) { err(1, "recvfrom"); } memcpy(&theader, tbuffer, sizeof(struct rx_header)); if (counter == ntohl(theader.callNumber)) break; } /* see if we've timed out */ if (endTime < time(0)) return -1; } code -= sizeof(struct rx_header); if (code > aresultLen) code = aresultLen; memcpy(aresult, tp, code); return code; } static int GetVersion(int asocket, uint32_t ahost, uint16_t aport, void *adata, long alen, char *aresult, long aresultLen) { static long counter = 100; long endTime; struct rx_header theader; char tbuffer[1500]; int code; struct timeval tv; struct sockaddr_in taddr, faddr; int faddrLen; fd_set imask; char *tp; endTime = time(0) + TIMEOUT; /* try for N seconds */ counter++; tp = &tbuffer[sizeof(struct rx_header)]; taddr.sin_family = AF_INET; taddr.sin_port = aport; taddr.sin_addr.s_addr = ahost; while(1) { memset(&theader, 0, sizeof(theader)); theader.epoch = htonl(999); theader.cid = 0; theader.callNumber = htonl(counter); theader.seq = 0; theader.serial = 0; theader.type = RX_PACKET_TYPE_VERSION; theader.flags = RX_CLIENT_INITIATED | RX_LAST_PACKET; theader.serviceId = 0; if (sizeof(theader) + alen > sizeof(tbuffer)) errx(1, "message to large"); memcpy(tbuffer, &theader, sizeof(theader)); memcpy(tp, adata, alen); code = sendto(asocket, tbuffer, alen+sizeof(struct rx_header), 0, (struct sockaddr *)&taddr, sizeof(struct sockaddr_in)); if (code == -1) { err(1, "sendto"); } if (asocket >= FD_SETSIZE) { printf("rxdebug: socket fd too large\n"); exit (1); } /* see if there's a packet available */ FD_ZERO(&imask); FD_SET(asocket, &imask); /* should be 1 */ tv.tv_sec = 10; tv.tv_usec = 0; code = select(asocket + 1, &imask, 0, 0, &tv); if (code == -1) { err(1, "select"); } if (code > 0) { /* now receive a packet */ faddrLen = sizeof(struct sockaddr_in); code = recvfrom(asocket, tbuffer, sizeof(tbuffer), 0, (struct sockaddr *)&faddr, &faddrLen); if (code == -1) { err(1, "recvfrom"); } memcpy(&theader, tbuffer, sizeof(struct rx_header)); if (counter == ntohl(theader.callNumber)) break; } /* see if we've timed out */ if (endTime < time(0)) return -1; } code -= sizeof(struct rx_header); if (code > aresultLen) code = aresultLen; memcpy(aresult, tp, code); return code; } static int MapOldConn (char version, struct rx_debugConn *tconn) { int i; struct rx_debugConn_vL *vL = (struct rx_debugConn_vL *)tconn; #define MOVEvL(a) (tconn->a = vL->a) if ((version <= RX_DEBUGI_VERSION_W_UNALIGNED_CONN) || (version > RX_DEBUGI_VERSION)) { /* any old or unrecognized version... */ for (i=0;ih_addr, sizeof(onlyHost)); } else onlyHost = 0xffffffff; if (onlyAuthName) { char *name = onlyAuthName; if (strcmp (name, "clear") == 0) onlyAuth = 0; else if (strcmp (name, "auth") == 0) onlyAuth = 1; else if (strcmp (name, "crypt") == 0) onlyAuth = 2; else if ((strcmp (name, "null") == 0) || (strcmp (name, "none") == 0) || (strncmp (name, "noauth", 6) == 0) || (strncmp (name, "unauth", 6) == 0)) onlyAuth = -1; else { fprintf (stderr, "Unknown authentication level: %s\n", name); exit (1); } } else onlyAuth = 999; /* lookup host */ if (hostName) { th = gethostbyname(hostName); if (!th) { printf("rxdebug: host %s not found in host table\n", hostName); exit(1); } memcpy(&host, th->h_addr, sizeof(host)); } else host = htonl(0x7f000001); /* IP localhost */ if (!portName) port = htons(7000); /* default is fileserver */ else { if ((port = PortNumber(portName)) == 0) port = PortName(portName); if (port == 0) { printf("rxdebug: can't resolve port name %s\n", portName); exit(1); } } dallyCounter = 0; hostAddr.s_addr = host; printf("Trying %s (port %d):\n", inet_ntoa(hostAddr), ntohs(port)); s = socket(AF_INET, SOCK_DGRAM, 0); memset(&taddr, 0, sizeof(taddr)); taddr.sin_family = AF_INET; taddr.sin_port = 0; taddr.sin_addr.s_addr = 0; code = bind(s, (struct sockaddr *)&taddr, sizeof(struct sockaddr_in)); if (code) { perror("bind"); exit(1); } if(version_flag) { nada[0] = '\0'; code = GetVersion(s, host, port, nada, length, version, length); if (code < 0) { printf("get version call failed with code %d, errno %d\n", code,errno); exit(1); } printf("AFS version: %s\n",version);fflush(stdout); exit(0); } tin.type = htonl(RX_DEBUGI_GETSTATS); tin.index = 0; code = MakeCall(s, host, port, (char *) &tin, sizeof(tin), (char *) &tstats, sizeof(tstats)); if (code < 0) { printf("getstats call failed with code %d\n", code); exit(1); } withSecStats = (tstats.version >= RX_DEBUGI_VERSION_W_SECSTATS); withAllConn = (tstats.version >= RX_DEBUGI_VERSION_W_GETALLCONN); withRxStats = (tstats.version >= RX_DEBUGI_VERSION_W_RXSTATS); withWaiters = (tstats.version >= RX_DEBUGI_VERSION_W_WAITERS); printf("Free packets: %ld, packet reclaims: %ld, calls: %ld, " "used FDs: %d\n", (long)ntohl(tstats.nFreePackets), (long)ntohl(tstats.packetReclaims), (long)ntohl(tstats.callsExecuted), tstats.usedFDs); if (!tstats.waitingForPackets) printf("not "); printf("waiting for packets.\n"); if (withWaiters) printf("%ld calls waiting for a thread\n", (long)ntohl(tstats.nWaiting)); if (rxstats && withRxStats) { if(!withRxStats) { fprintf (stderr, "WARNING: Server doens't support " "retrieval of Rx statistics\n"); } else { struct rx_stats rxstats; int i; uint32_t *lp; memset (&rxstats, 0, sizeof(rxstats)); tin.type = htonl(RX_DEBUGI_RXSTATS); tin.index = 0; /* should gracefully handle the case where rx_stats grows */ code = MakeCall(s, host, port, (char *) &tin, sizeof(tin), (char *) &rxstats, sizeof(rxstats)); if (code < 0) { printf("rxstats call failed with code %d\n", code); exit(1); } if ((code == sizeof(tin)) && (ntohl(((struct rx_debugIn *)(&rxstats))->type) == RX_DEBUGI_BADTYPE)) { fprintf (stderr, "WARNING: Server doens't support " "retrieval of Rx statistics\n"); } else { if (code != sizeof(rxstats)) { /* handle other versions?... */ fprintf (stderr, "WARNING: returned Rx statistics of " "unexpected size (got %d)\n", code); } /* Since its all int32's, convert to host order with a loop. */ lp = (uint32_t*)&rxstats; for (i=0; i< sizeof(rxstats)/sizeof(uint32_t); i++) lp[i] = ntohl(lp[i]); rx_PrintTheseStats (stdout, &rxstats, sizeof(rxstats)); } } } if (noConns) return 0; tin.type = htonl(RX_DEBUGI_GETCONN); if (allconns) tin.type = htonl(RX_DEBUGI_GETALLCONN); if (onlyServer) printf ("Showing only server connections\n"); if (onlyClient) printf ("Showing only client connections\n"); if (onlyAuth != 999) { static char *name[] = {"unauthenticated", "rxkad_clear", "rxkad_auth", "rxkad_crypt"}; printf ("Showing only %s connections\n", name[onlyAuth+1]); } if (onlyHost != 0xffffffff) { hostAddr.s_addr = onlyHost; printf ("Showing only connections from host %s\n", inet_ntoa(hostAddr)); } if (onlyPort != 0xffff) printf ("Showing only connections on port %u\n", ntohs(onlyPort)); for(i=0;;i++) { tin.index = htonl(i); memset (&tconn, 0, sizeof(tconn)); code = MakeCall(s, host, port, (char *)&tin, sizeof(tin), (char *) &tconn, sizeof(tconn)); if (code < 0) { printf("getconn call failed with code %d\n", code); break; } MapOldConn (tstats.version, &tconn); if (tconn.cid == htonl(0xffffffff)) { printf("Done.\n"); break; } /* see if we're in nodally mode and all calls are dallying */ if (nodally) { flag = 0; for(j=0;j (double) from working, * this code produces negative lifetimes when run on the * RT. */ printf (", expires in %.1f hours", ((u_long)ntohl(tconn.secStats.expires) - time(0)) / 3600.0); if (!(flags & 1)) { printf ("\n Received %lu bytes in %lu packets\n", (long)ntohl(tconn.secStats.bytesReceived), (long)ntohl(tconn.secStats.packetsReceived)); printf (" Sent %lu bytes in %lu packets\n", (long)ntohl(tconn.secStats.bytesSent), (long)ntohl(tconn.secStats.packetsSent)); } else printf ("\n"); break; } default: printf(" unknown\n"); } } for(j=0;j", NULL }, {"onlyhost", 0, aarg_string, &onlyHostName, "show only ", NULL }, {"onlyauth", 0, aarg_string, &onlyAuthName, "show only ", NULL }, {"version", 0, aarg_flag, &version_flag, "show AFS version id", NULL }, {"noconns", 0, aarg_flag, &noConns, "show no connections", NULL }, {NULL} }; static void usage(void) { aarg_printusage (args, "rxdebug", "", AARG_AFSSTYLE); } /* simple main program */ int main(int argc, char **argv) { int optind = 0; if (agetarg (args, argc, argv, &optind, AARG_AFSSTYLE)) { usage(); return 0; } if(helpflag) { usage(); return 0; } argc -= optind; argv += optind; if (argc > 0) { fprintf (stderr, "create volume: unparsed arguments\n"); return 0; } return MainCommand(); }