home *** CD-ROM | disk | FTP | other *** search
- Path: sparky!uunet!spool.mu.edu!agate!dog.ee.lbl.gov!lbl.gov!vxwexplo
- From: Mandler <rcm@ssd.ray.com>
- Newsgroups: comp.os.vxworks
- Subject: re: ping command available?
- Date: Fri, 22 Jan 1993 11:03:48 -0500
- Organization: Lawrence Berkeley Laboratory, Berkeley CA
- Lines: 741
- Sender: vxwexplo@lbl.gov
- Message-ID: <199301221603.AA21789@piranha.ssd.ray.com>
- NNTP-Posting-Host: 128.3.112.16
- Originator: daemon@vxw.ee.lbl.gov
-
- To thoff and other interested parties,
- Here is a "quick and dirty" version of the ping program that we ported to
- VxWorks.
- ______________________________________________________________
- | Roland C Mandler, Raytheon Submarine Signal Division |
- | 1847 West Main Road, Mail Stop 188 |
- | Portsmouth, RI 02871-1087 (401) 847-8000 (X4228) |
- | |
- | {uiucdcs,uunet}!rayssd!sgfb.ssd.ray.com!rcm |
- |______________________________________________________________|
-
-
- /* Includes, defines and global variables used between functions.
- */
- #include "vxWorks.h"
- #include "mbuf.h"
- #include "ctype.h"
- #include "socket.h"
- #include "if.h"
- #include "ioLib.h"
- #include "ioctl.h"
- #include "iosLib.h"
- #include "stdioLib.h"
- #include "selectLib.h"
- #include "sockLib.h"
- #include "in_systm.h"
- #include "in.h"
- #include "ip.h"
- #include "ip_icmp.h"
- #include "taskLib.h"
- #include "hostLib.h"
- #include "wdLib.h"
- #include "errno.h"
-
- extern int errno;
-
- /* defines */
- /*
- * Beware that the outgoing packet starts with the ICMP header and
- * does not include the IP header (the kernel prepends that for us).
- * But, the received packet includes the IP header.
- */
- #define DEF_DATALEN 56 /* default data area after ICMP header */
- #ifndef INADDR_NONE
- #define INADDR_NONE 0xffffffff /* should be in <in.h> */
- #endif
- #ifndef MAXHOSTNAMELEN
- #define MAXHOSTNAMELEN 64 /* should be defined in <param.h> */
- #endif
- #define MAXMSG 1 /* number of messages pipe will hold */
- #define MAXPIPE 1 /* number of bytes in pipe message */
- #define MAXPACKET 4096 /* max packet size */
- #define MAXWAIT 10 /* max time to wait for response, sec. */
- /* used only for final receive */
- #define NROUTES 9 /* number of record route slots */
- #define PF_ICMP 1 /* ICMP protocol */
- #define QUIET 2 /* quiet flag */
- #define RROUTE 8 /* record route flag */
- #define SIZE_ICMP_HDR 8 /* 8-byte ICMP header */
- #define SIZE_TIME_DATA 8 /* then the BSD timeval struct (ICMP "data") */
-
- /* variables */
- int datalen; /* size of data after the ICMP header */
- /* may be 0 */
- /* if >= SIZE_TIME_DATA, timing is done */
- char *destdotaddr;
- char *hostname;
- short ident; /* masked process ID, to identify returns */
- int mytask; /* full process ID */
- int npackets; /* max # of packets to send; 0 if no limit */
- int nreceived; /* # of packets we got back */
- int ntransmitted; /* sequence # for outbound packets = #sent */
- int pingflags;
- int packsize; /* size of ICMP packets to send */
- /* this includes the 8-byte ICMP header */
- char pipecode;
- int pipefd; /* pipe file descriptor */
- int pipestat;
- u_char recvpack[MAXPACKET]; /* the received packet */
- char rspace[3+4*NROUTES+1]; /* record route space */
- long sbytes;
- u_char sendpack[MAXPACKET]; /* the packet we send */
- int sockfd; /* socket file descriptor */
- int time_start;
- int time_ret;
- int timing; /* true if time-stamp in each packet */
- int tmin; /* min round-trip time */
- int tmax; /* max round-trip time */
- long tsum; /* sum of all round-trip times, for average */
- /* above 3 times are in milliseconds */
- int verbose; /* enables additional error messages */
-
- /* structures */
- struct fd_set fdset; /*file descriptor bit mapping for select */
- struct fd_set *fdst;
- struct sockaddr_in dest; /* who to ping */
- WDOG_ID wdtmr;
-
-
- /* routines */
- char *inet_ntoa(); /* BSD library routine */
- VOID ping_task();
- VOID finish(); /* our function to finish up and exit */
- VOID stp();
- VOID timeout_hndl();
- VOID parseOptions();
-
- /*
- * Copyright (c) 1987 Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by the University of California, Berkeley. The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
- #ifndef lint
- char copyright[] =
- "@(#) Copyright (c) 1987 Regents of the University of California.\n\
- All rights reserved.\n";
- #endif /* not lint */
-
- #ifndef lint
- static char sccsid[] = "@(#)ping.c 4.10 (Berkeley) 10/10/88";
- #endif /* not lint */
-
-
- /*
- * P I N G . C
- *
- * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility,
- * measure round-trip-delays and packet loss across network paths.
- *
- * Author -
- * Mike Muuss
- * U. S. Army Ballistic Research Laboratory
- * December, 1983
- * Modified at Uc Berkeley
- *
- * This version was modified to run under vxWorks by:
- * Roland Mandler
- * Raytheon Submarine Signal Division
- * June, 1991
- *
- * Status -
- * Public Domain. Distribution Unlimited.
- *
- * Bugs -
- * More statistics could always be gathered.
- * This program has to run SUID to ROOT to access the ICMP socket.
- */
-
- char usage[] =
- "\nUsage: \
- ping [-dnqrvRs] host [datasize [count]] \n\
- \n\
- STANDARD OPTIONS: \n\
- -s = continuous -d = debug -q = quiet -v = verbose \n\
- -R = record route -r = route to interface \n\
- \n\
- ";
- char hnamebuf[MAXHOSTNAMELEN];
- char *pname;
-
- ping(strng)
- char strng[];
- {
- /* spawn off ping task - makes it easier to kill */
- taskSpawn(NULL, 1, VX_STDIO | VX_DEALLOC_STACK,20000,&ping_task,
- strng,0,0,0,0,0,0,0,0,0);
- }
-
- VOID ping_task(strng)
- char strng[];
- {
- int sockoptions,on;
- int host;
- int pargc;
- int i, i1, i2, i3, i4;
- unsigned char ttl, loop;
- struct in_addr ifaddr;
- char *argvpar[11];
- char **pargv = argvpar;
-
- /* parse input string into argc, argv format */
- parseOptions(&pargc,pargv,strng);
-
- on = 1;
- pname = pargv[0];
- pargc--;
- pargv++;
-
- fdst = (struct fd_set *)&fdset;
- sockoptions = 0;
- pingflags = 0;
- ntransmitted = 0;
- nreceived = 0;
- verbose = 0;
- timing = 0;
- tmin = 0;
- tmax = 0;
- npackets = 1; /* default is send one ping */
- tmin = 0;
- tmax = 0;
- tsum = 0;
- wdtmr = wdCreate();
- while (pargc > 0 && *pargv[0] == '-') {
- while (*++pargv[0]) switch (*pargv[0]) {
- case 'd': /* debug on */
- sockoptions |= SO_DEBUG;
- break;
- case 'r': /* route to intfc */
- sockoptions |= SO_DONTROUTE;
- break;
- case 'v': /* verbose input error printout */
- verbose++;
- break;
- case 's': /* continuous pinging at 1 Hz */
- npackets = 0; /* 1 Hz continuous pinging */
- printf("\n\nTYPE 'stp' TO ABORT \n\n");
- break;
- case 'q': /* disables ping send/recv messages */
- pingflags |= QUIET;
- break;
- case 'R': /* record route */
- pingflags |= RROUTE;
- break;
- default:
- goto print_usage;
- }
- pargc--, pargv++;
- }
- if (pargc < 1) {
- print_usage: printf(usage);
- return;
- }
-
- /*
- * Assume the host is specified by numbers (Internet dotted-decimal)
- * and call inet_addr() to convert it. If that doesn't work, then
- * assume its a name and call hostGetByName() to look it up.
- */
-
- bzero((char *) &dest, sizeof(dest));
- dest.sin_family = AF_INET;
-
- if ( (dest.sin_addr.s_addr = htons(inet_addr(pargv[0]))) != INADDR_NONE) {
- strcpy(hnamebuf, pargv[0]);
- hostname = hnamebuf;
- destdotaddr = NULL;
- } else {
- if ( (host = htons(hostGetByName(pargv[0]))) == NULL) {
- printf("host name error: %s ", pargv[0]);
- }
- dest.sin_family = AF_INET;
- dest.sin_addr.s_addr = host;
- strcpy(hnamebuf,pargv[0]);
- hostname = hnamebuf;
- destdotaddr = inet_ntoa(dest.sin_addr.s_addr);
- /* convert to dotted-decimal notation */
- }
-
- /*
- * If the user specifies a size, that is the size of the data area
- * following the ICMP header that is transmitted. */
-
- if (pargc >= 2)
- sscanf(pargv[1],"%d",&datalen);
- else
- datalen = DEF_DATALEN;
-
- packsize = datalen + SIZE_ICMP_HDR;
- if (packsize > MAXPACKET)
- printf("packet size too large");
- if (datalen >= SIZE_TIME_DATA)
- timing = 1;
-
- /*
- * The user can specify the maximum number of packets to receive.
- */
-
- if (pargc > 2) {
- sscanf(pargv[2],"%d",&npackets);
- printf("\n\nTYPE 'stp' TO ABORT \n\n");
- }
-
- /*
- * Fetch our process ID. We use that as the "ident" field
- * in the ICMP header, to identify this process' packets.
- * This allows multiple copies of ping to be running on a host
- * at the same time. This identifier is needed to separate
- * the received ICMP packets (since all readers of an ICMP
- * socket get all the received packets).
- */
-
- mytask = taskIdSelf();
- ident = mytask & 0x7fff;
-
- /*
- * Create the socket.
- */
-
- if ( (sockfd = socket(AF_INET, SOCK_RAW, PF_ICMP)) < 0)
- printf("can't create raw socket");
- if (sockoptions & SO_DEBUG)
- if (setsockopt(sockfd, SOL_SOCKET, SO_DEBUG, &on,
- sizeof(on)) < 0)
- printf("setsockopt SO_DEBUG error");
- if (sockoptions & SO_DONTROUTE)
- if (setsockopt(sockfd, SOL_SOCKET, SO_DONTROUTE, &on,
- sizeof(on)) < 0)
- printf("setsockopt SO_DONTROUTE error");
- /* Record Route option */
- if( pingflags & RROUTE ) {
- #ifdef IP_OPTIONS
- rspace[IPOPT_OPTVAL] = IPOPT_RR;
- rspace[IPOPT_OLEN] = sizeof(rspace)-1;
- rspace[IPOPT_OFFSET] = IPOPT_MINOFF;
- if( setsockopt(sockfd, IPPROTO_IP, IP_OPTIONS, rspace, sizeof(rspace)) < 0 ) {
- printf( "Record route" );
- return;
- }
- #else
- printf( "ping: record route not available on this machine.\n" );
- return;
- #endif IP_OPTIONS
- }
-
-
- /* create a communication pipe */
- pipeDevCreate("ping_pipe",MAXMSG,MAXPIPE);
-
- if ((pipefd = open("ping_pipe", O_RDWR, (int) NULL)) == ERROR)
- {
- printf("error: can't open pipe.\n");
- return;
- }
-
- /* set up bit map to select on pipe or socket i/o */
- FD_SET(sockfd, fdst);
- FD_SET(pipefd, fdst);
-
- do_ping(); /* start the output going */
- return;
- }
-
- /* This routine is the watchdog timer handler. It writes a timeout indication
- * to the pipe, which is in turn handled within 'do_ping' */
-
- VOID timeout_hndl()
- {
- write(pipefd, "t", 1);
- }
-
-
- /* This routine controls ping origination and reception */
-
- do_ping()
- {
- int finflag;
- register int n;
- int fromlen;
- struct sockaddr_in from;
- int cont;
-
- for ( ; ; ) {
-
- send_ping(); /* first send a packet */
-
- if (npackets != 0)
- /*
- * We've sent the specified number of packets.
- * But, we can't just terminate, as there is at least one
- * packet still to be received (the one we sent at the
- * beginning of this function).
- * Just wait 10 seconds.
- */
- wdStart (wdtmr, MAXWAIT * sysClkRateGet(), timeout_hndl);
-
- /* wait for either socket or pipe data availability */
-
- if ( select (32,&fdset,NULL,NULL,NULL) > 0 ) {
- if (FD_ISSET(pipefd,fdst)) {
- pipestat = read (pipefd,&pipecode, MAXPIPE);
- finish();
- break; /* escape the loop and exit the program */
- } /* pipe data pending */
-
- if (FD_ISSET(sockfd,fdst)) {
-
- fromlen = sizeof(from);
- if ( (n = recvfrom(sockfd, recvpack, sizeof(recvpack), 0,
- (struct sockaddr *) &from, &fromlen)) < 0) {
- if (errno == EINTR)
- continue; /* normal */
- printf("recvfrom error");
- break;
- }
- /* cancel 10 second timeout */
- wdCancel(wdtmr);
-
- /* check the receive packet */
- pr_pack(recvpack, n, &from);
-
- /*
- * If we're only supposed to receive a certain number of
- * packets, and we've reached the limit, stop.
- */
-
- if (npackets && (nreceived >= npackets)) {
- finish();
- break;
- }
- /* wait 1 second before pinging again */
- taskDelay(sysClkRateGet());
-
- } /* socket data pending */
- } /* select data available */
- } /* loop */
- return;
- }
- /*
- * Compose and transmit an ICMP ECHO REQUEST packet. The IP header
- * will be prepended by the kernel. The ID field is our process ID,
- * and the sequence number is an ascending integer. The first 8 bytes
- * of the data portion are used to hold a BSD "timeval" struct in host
- * byte-order, to compute the round-trip time of each packet.
- */
-
-
- send_ping()
- {
- register int i;
- register struct icmp *icp; /* ICMP header */
- register u_char *uptr; /* start of user data */
-
- /*
- * Fill in the ICMP header.
- */
-
- icp = (struct icmp *) sendpack; /* pointer to ICMP header */
- icp->icmp_type = ICMP_ECHO;
- icp->icmp_code = 0;
- icp->icmp_cksum = 0; /* init to 0, then call in_cksum() below */
- icp->icmp_id = ident; /* our pid, to identify on return */
- icp->icmp_seq = ntransmitted++; /* sequence number */
-
- /*
- * And fill in the remainder of the packet with the user data.
- * We just set each byte of udata[i] to i (although this is
- * not verified when the echoed packet is received back).
- */
-
- uptr = &sendpack[SIZE_ICMP_HDR + SIZE_TIME_DATA];
- for (i = SIZE_TIME_DATA; i < datalen; i++)
- *uptr++ = i;
-
- /*
- * Compute and store the ICMP checksum (now that we've filled
- * in the entire ICMP packet). The checksum includes the ICMP
- * header, the time stamp, and our user data.
- */
-
- icp->icmp_cksum = icmp_cksum(icp, packsize);
-
- /*
- * Add the time stamp of when we sent it.
- */
-
- if (timing)
- time_start = tickGet();
-
- /*
- * Now send the datagram.
- */
-
- i = sendto(sockfd, sendpack, packsize, 0,
- (struct sockaddr *) &dest, sizeof(dest));
-
- /* tell the user it went out */
- if ((pingflags & QUIET) == 0)
- {
- printf("PING %s", hostname);
- if (destdotaddr)
- printf(" (%s)", destdotaddr);
- printf(": %d data bytes\n", datalen);
- setlinebuf(stdout); /* one line at a time */
- }
-
- if (i < 0 || i != packsize) {
- if (i < 0)
- printf("sendto error");
- else
- printf("wrote %s %d bytes, return=%d",
- hostname, packsize, i);
- }
- }
- /*
- * I C M P _ C K S U M
- *
- * Checksum routine for Internet Protocol family headers (C Version)
- *
- */
- icmp_cksum(addr, len)
- u_short *addr;
- int len;
- {
- register int nleft = len;
- register u_short *w = addr;
- register int sum = 0;
- u_short answer = 0;
-
- /*
- * Our algorithm is simple, using a 32 bit accumulator (sum),
- * we add sequential 16 bit words to it, and at the end, fold
- * back all the carry bits from the top 16 bits into the lower
- * 16 bits.
- */
- while( nleft > 1 ) {
- sum += *w++;
- nleft -= 2;
- }
-
- /* mop up an odd byte, if necessary */
- if( nleft == 1 ) {
- *(u_char *)(&answer) = *(u_char *)w ;
- sum += answer;
- }
-
- /*
- * add back carry outs from top 16 bits to low 16 bits
- */
- sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
- sum += (sum >> 16); /* add carry */
- answer = ~sum; /* truncate to 16 bits */
- return (answer);
- }
-
-
- /*
- * Print out the packet, if it came from us. This logic is necessary
- * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
- * which arrive ('tis only fair). This permits multiple copies of this
- * program to be run without having intermingled output (or statistics!).
- */
-
-
- pr_pack(buf, cc, from)
- char *buf; /* ptr to start of IP header */
- int cc; /* total size of received packet */
- struct sockaddr_in *from; /* address of sender */
- {
- int i, iphdrlen, triptime;
- struct ip *ip; /* ptr to IP header */
- register struct icmp *icp; /* ptr to ICMP header */
- long *lp;
- struct timeval tv;
- char *pr_type();
-
- from->sin_addr.s_addr = ntohl(from->sin_addr.s_addr);
-
- if (timing)
- time_ret = tickGet();
-
- /*
- * We have to look at the IP header, to get its length.
- * We also verify that what follows the IP header contains at
- * least an ICMP header (8 bytes minimum).
- */
-
- ip = (struct ip *) buf;
- iphdrlen = ip->ip_hl << 2; /* convert # 16-bit words to #bytes */
- if (cc < iphdrlen + ICMP_MINLEN) {
- if (verbose)
- printf("packet too short (%d bytes) from %s\n", cc,
- inet_ntoa(ntohl(from->sin_addr.s_addr)));
- return;
- }
- cc -= iphdrlen;
-
- icp = (struct icmp *)(buf + iphdrlen);
- if (icp->icmp_type != ICMP_ECHOREPLY) {
- /*
- * The received ICMP packet is not an echo reply.
- * If the verbose flag was set, we print the first 48 bytes
- * of the received packet as 12 longs.
- */
-
- if (verbose) {
- lp = (long *) buf; /* to print 12 longs */
- printf("%d bytes from %s: ", cc,
- inet_ntoa(ntohl(from->sin_addr.s_addr)));
- printf("icmp_type=%d (%s)\n",
- icp->icmp_type, pr_type(icp->icmp_type));
- for (i = 0; i < 12; i++)
- printf("x%2.2x: x%8.8x\n", i*sizeof(long), *lp++);
- printf("icmp_code=%d\n", icp->icmp_code);
- }
- return;
- }
-
- /*
- * See if we sent the packet, and if not, just ignore it.
- */
-
- if (icp->icmp_id != ident)
- return;
-
- if ((pingflags & QUIET) == 0)
- {
- printf("%d bytes from %s: ", cc,
- inet_ntoa(ntohl(from->sin_addr.s_addr)));
- printf("ping # = %d. \n ", icp->icmp_seq);
- }
- if (timing) {
- /* Calculate the round-trip time, and update the min/avg/max */
- triptime =(time_ret - time_start) * (1000 /sysClkRateGet());
- tsum += triptime;
- if (triptime < tmin)
- tmin = triptime;
- if (triptime > tmax)
- tmax = triptime;
- }
-
- nreceived++; /* only count echo reply packets that we sent */
- }
-
- /*
- * Convert an ICMP "type" field to a printable string.
- * This is called for ICMP packets that are received that are not
- * ICMP_ECHOREPLY packets.
- */
-
- char *
- pr_type(t)
- register int t;
- {
- static char *ttab[] = {
- "Echo Reply",
- "ICMP 1",
- "ICMP 2",
- "Dest Unreachable",
- "Source Quence",
- "Redirect",
- "ICMP 6",
- "ICMP 7",
- "Echo",
- "ICMP 9",
- "ICMP 10",
- "Time Exceeded",
- "Parameter Problem",
- "Timestamp",
- "Timestamp Reply",
- "Info Request",
- "Info Reply"
- };
-
- if (t < 0 || t > 16)
- return("OUT-OF-RANGE");
-
- return(ttab[t]);
- }
-
- /*
- * parseOptions.c
- * Generate Unix style (argc, argv) parameters from an incoming
- * VxWorks command string. Chops up the original string with
- * nulls to make short strings and fills the argv array with pointers
- * to the new strings.
- *
- * maximum of 10 parameters should be defined. (argv[11] in caller).
- * parameters should be seperated by blanks or tabs.
- */
- VOID
- parseOptions(argc, argv, inpStr)
- int *argc; /* argument count */
- char *argv[]; /* argument pointers */
- char *inpStr; /* original input line */
- {
- char *cch; /* current character */
-
- cch = inpStr;
- *argc = 1; /* always at least 1 */
-
- while (*cch != '\0')
- {
- while (((*cch == ' ') || (*cch == ' ')) && (*cch != '\0'))
- cch++;
-
-
- if (*cch != '\0')
- {
- argv[*argc] = cch;
- *argc += 1;
-
- while ((*cch != ' ') && (*cch != ' ') &&
- (*cch != '\0'))
- cch++;
- if (*cch != '\0')
- *cch++ = '\0';
- }
- }
- }
-
- /*
- * Print out statistics, and stop.
- */
-
-
- VOID finish()
- {
- printf("\n----%s PING Statistics----\n", hostname );
- printf("%d packets transmitted, ", ntransmitted );
- printf("%d packets received, ", nreceived );
- if (ntransmitted)
- printf("%d%% packet loss",
- (int) (((ntransmitted-nreceived)*100) / ntransmitted) );
- printf("\n");
- if (nreceived && timing)
- printf("round-trip (ms) min/avg/max = %d/%d/%d\n",
- tmin, tsum / nreceived, tmax );
- wdCancel(wdtmr);
- close(pipefd);
- close(sockfd);
- printf("PING done. Hit <return>.\n");
- taskDelete(mytask);
- }
- /* termination of continuous pinging */
-
- VOID stp()
- {
- finish();
- }
-