#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 1 (of 1)."
# Contents:  ping ping/Makefile ping/README ping/ping.c
# Wrapped by thor@thor on Tue Mar  1 07:25:58 1994
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test ! -d 'ping' ; then
    echo shar: Creating directory \"'ping'\"
    mkdir 'ping'
fi
if test -f 'ping/Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'ping/Makefile'\"
else
echo shar: Extracting \"'ping/Makefile'\" \(707 characters\)
sed "s/^X//" >'ping/Makefile' <<'END_OF_FILE'
X#
X#	Makefile for 
X#	Author:
X#	Date:
X#
X# GNU C 
XCC= gcc68
X# Cross linker
XLD = ld68k
X#
X# Totally agressive optimization.
XOPT= -O2
X#
XDEFINES=
X#
X# Drag in includes from here.
XINCLUDES= -I/vx/h
X#
XCFLAGS= $(OPT) $(DEFINES) $(INCLUDES)
X#
XLIBS=
X#
XOBJS= ping.o
X#
XSRCS= ping.c
X#
XHEADERS=
X#
X# Include files go here.
XINC=
X#
X# Binaries go here.
XBIN=
X
X.KEEP_STATE:
X.MAIN: all
X
Xall: $(OBJS)
X
Xupdate:
X	-for i in $(HEADERS); \
X		do (diff $$i $(INC)/$$i >tmpdiff; \
X			if test -s tmpdiff; \
X			then \
X				(echo "Copying $$i";cp $$i $(INC)) \
X			fi;); \
X	rm tmpdiff; \
X	done;
X	install $(OBJS) $(BIN)		
X
Xasm:
X	for i in $(SRCS); \
X		do (echo "$(CC) -S $(CFLAGS) $$i";$(CC) -S $(CFLAGS) $$i); \
X	done;
X
Xclean:
X	rm -f *.o *~ core
END_OF_FILE
if test 707 -ne `wc -c <'ping/Makefile'`; then
    echo shar: \"'ping/Makefile'\" unpacked with wrong size!
fi
# end of 'ping/Makefile'
fi
if test -f 'ping/README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'ping/README'\"
else
echo shar: Extracting \"'ping/README'\" \(495 characters\)
sed "s/^X//" >'ping/README' <<'END_OF_FILE'
X	I have no idea of the direct descent of this code beyond the
Xlittle said in the file. I've modified it to be ANSI C compatible. Also
XI hacked it to die cleanly. There are two callable entry points:
X
Xping(char *target) - Which simply pings until a control-C is entered.
Xpingn(char *target, int n) - Which stops after n tries.
X
XThere are two defines of interest:
X
X-DPRE51
Xallows compilation under VxWorks versions prior to 5.1.
X
X-DCLK_TCK=n
Xsets the tick rate to be n per second. defaults to 60.
END_OF_FILE
if test 495 -ne `wc -c <'ping/README'`; then
    echo shar: \"'ping/README'\" unpacked with wrong size!
fi
# end of 'ping/README'
fi
if test -f 'ping/ping.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'ping/ping.c'\"
else
echo shar: Extracting \"'ping/ping.c'\" \(15418 characters\)
sed "s/^X//" >'ping/ping.c' <<'END_OF_FILE'
X/*
X * Copyright (c) 1987 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Berkeley.  The name of the
X * University may not be used to endorse or promote products derived
X * from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X */
X
X#ifndef lint
Xchar copyright[] =
X"@(#) Copyright (c) 1987 Regents of the University of California.\n\
X All rights reserved.\n";
X#endif /* not lint */
X
X#ifndef lint
Xstatic char sccsid[] = "@(#)ping.c	4.10 (Berkeley) 10/10/88";
X#endif /* not lint */
X
X/*
X *			P I N G . C
X *
X * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility,
X * measure round-trip-delays and packet loss across network paths.
X *
X * Usage: ping host
X *
X * 	where "host" can either be an address in internet format (e.g.,
X *	123.45.67.89), or a hostname (e.g., mars).
X *
X * 	The options for the usual ping aren't supported from the command line
X *	as such, but may be compiled in.  To do this:
X *
X *		verbose = 1		List ICMP packets other than ECHO
X *					RESPONSE that are received.
X *		
X *		options |= SO_DEBUG	Display debugging information.
X *		
X *		options |= SO_DONTROUTE	Bypass the normal routing tables and
X *					send directly to a host on an attached
X *					network.  If the host is not on a
X *					directly attached network, an error is
X *					returned.  This option can be used to
X *					ping a local host through an interface
X *					that has no route through it (e.g.,
X *					after the interface was dropped by
X *					routed).
X *
X *		datalen			Default datagram length is 64 bytes,
X *					but this can be changed by setting this
X *					to some other length.
X *
X *		npackets		If this is non-zero, only this number of
X *					requests is sent.  Otherwise ping will
X *					continue until explicitly killed.
X *
X *	Ping sends one datagram per second and prints one line of output for
X *	every ECHO RESPONSE returned.  No output is produced if there is no
X *	response.  Round-trip times and packet loss statistics are computed.
X *	Time resolution is only as good as the clock on your board.  Be sure to
X *	set CLK_TCK to the number of clock ticks per second to get an accurate
X *	reading.  When all responses have been received (npackets != 0), or
X *	the program is somehow terminated (e.g., "td"), ping displays a brief
X *	summary.
X *
X * Author -
X *	Mike Muuss
X *	U. S. Army Ballistic Research Laboratory
X *	December, 1983
X *
X * 	Modified at Uc Berkeley
X * 	Modified at Hughes Network Systems for VxWorks.
X *      Modified at National Center for Atmospheric Research
X *
X * Status -
X *	Public Domain.  Distribution Unlimited.
X *
X * Bugs -
X *	More statistics could always be gathered.
X */
X
X#include <vxWorks.h>
X#include <types.h>
X#include <sigLib.h>
X#include <wdLib.h>
X#include <stdioLib.h>
X#include <socket.h>
X#include <sockLib.h>
X#include <errno.h>
X#include <inetLib.h>
X#include <semLib.h>
X#include <taskLib.h>
X#include <in.h>
X
X#ifdef PRE_51
X#include <net/in_systm.h>
X#include <net/ip.h>
X#include <net/ip_icmp.h>
X#else
X#include <netinet/in_systm.h>
X#include <netinet/ip.h>
X#include <netinet/ip_icmp.h>
X#endif
X
X#ifndef CLK_TCK
X#define CLK_TCK		60	/* 100 ticks per second */
X#endif
X
X#define	MAXWAIT	(10 * CLK_TCK)	/* max time to wait for response, sec. */
X#define	MAXPACKET	4096	/* max packet size */
X#ifndef MAXHOSTNAMELEN
X#define MAXHOSTNAMELEN	64
X#endif
X
X#define ICMP_PROTO	1
X
Xstatic int	verbose = 1;
Xstatic u_char	packet[MAXPACKET];
Xstatic int	options;
Xextern	int errno;
X
Xstatic int sfd;			/* Socket file descriptor */
X
Xstatic struct sockaddr whereto;/* Who to ping */
Xstatic int datalen;		/* How much data */
X
Xstatic char usage[] = "Usage:  ping host\n";
X
Xstatic char *hostname;
Xstatic char hnamebuf[MAXHOSTNAMELEN];
X
Xstatic int npackets;
Xstatic int ntransmitted = 0;	/* sequence # for outbound packets = #sent */
Xstatic int ident;
X
Xstatic int nreceived = 0;	/* # of packets we got back */
Xstatic int timing = 0;
Xstatic int tmin = 999999999;
Xstatic int tmax = 0;
Xstatic int tsum = 0;		/* sum of all times, for doing average */
X
Xstatic WDOG_ID	timer = NULL;
Xstatic int pingTid;		/* Pinger's task id */
Xstatic int mainTid;		/* Main code's task id */
Xstatic SEM_ID pingSem = NULL;	/* Semaphore to say it's ok to ping */
X
X#ifdef __STDC__
Xint ping(char *);
Xint pingn(char *, int);
X
Xstatic void finish(void), catcher(void), pinger(void), die(void);
Xstatic void pr_pack(char *, int, struct sockaddr_in *);
Xstatic char *pr_type(int);
Xstatic in_cksum(u_short *, int);
X#else
Xint ping();
Xint pingn();
X
Xstatic void finish(), catcher(), pinger(), die();
Xstatic void pr_pack();
Xstatic char *pr_type();
Xstatic in_cksum();
X#endif __STDC__
X/*
X * 			M A I N
X */
X#ifdef __STDC__
Xint ping(char *host)
X#else
Xint ping(host)
Xchar *host;
X#endif
X{
X    return (pingn(host,0));	/* Invoke code with limitless number */
X				/* of pings. */
X}
X
X/* If pingn is called with np == 0, it will run until interrupted, */
X/* else it will exit after np pings. */
X#ifdef __STDC__
Xint pingn(FAST char *host, FAST int np)
X#else
Xint pingn(host,np)
XFAST char *host;
XFAST int np;
X#endif
X{
X    struct sockaddr_in from;
X    char *toaddr = NULL;
X    struct sockaddr_in *to = (struct sockaddr_in *) &whereto;
X    int on = 1,
X    hostaddr;
X    struct protoent *proto;
X
X    mainTid = taskIdSelf();	/* In case we need to be killed. */
X
X    bzero( (char *)&whereto, sizeof(struct sockaddr) );
X    to->sin_family = AF_INET;
X    to->sin_addr.s_addr = inet_addr(host);
X    if (to->sin_addr.s_addr != -1) {
X	strcpy(hnamebuf, host);
X	hostname = hnamebuf;
X    } else {
X	to->sin_addr.s_addr = hostGetByName(host);
X	if (hostaddr == ERROR) {
X	    printf("ping: %s: ", host);
X	    printErrno(0);
X	    exit(1);
X	}
X	to->sin_family = AF_INET;
X	strcpy(hnamebuf, host);
X	hostname = host;
X	toaddr = inet_ntoa(to->sin_addr);
X    }
X    
X    datalen = 64-8;
X    if (datalen > MAXPACKET) {
X	fprintf(stderr, "ping: packet size too large\n");
X	exit(1);
X    }
X    if (datalen >= sizeof(unsigned long int))
X      timing = 1;
X    
X    ident = taskIdSelf() & 0xFFFF;
X    
X    if ((sfd = socket(AF_INET, SOCK_RAW, ICMP_PROTO)) < 0) {
X	perror("ping: socket");
X	exit(5);
X    }
X    if (options & SO_DEBUG)
X      setsockopt(sfd, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof(on));
X    if (options & SO_DONTROUTE)
X      setsockopt(sfd, SOL_SOCKET, SO_DONTROUTE, (char *)&on, sizeof(on));
X    
X    printf("PING %s", hostname);
X    if (toaddr)
X      printf(" (%s)", toaddr);
X    printf(": %d data bytes\n", datalen);
X    
X    
X    setlinebuf( stdout );
X    taskDeleteHookAdd(finish);
X    
X    if ((timer = wdCreate()) == NULL) {
X	perror("wdCreate");
X	exit(1);
X    }
X
X    npackets = np;		/* Must reset these! */
X    ntransmitted = 0;
X    nreceived = 0;
X
X    catcher();	/* start things going */
X    
X    for (;;) {
X	int len = sizeof (packet);
X	int fromlen = sizeof (from);
X	int cc;
X	
X	if ( (cc=recvfrom(sfd, packet, len, 0,
X			  (struct sockaddr *)&from, &fromlen)) < 0) {
X	    if( errno == EINTR )
X	      continue;
X	    perror("ping: recvfrom");
X	    continue;
X	}
X	pr_pack( packet, cc, &from );
X	if (npackets && nreceived >= npackets)
X	  {
X	      finish();
X	      if (nreceived)
X		return(OK);		/* Force control back to caller. */
X	      else
X		return(ERROR);
X	  }
X    }
X    /*NOTREACHED*/
X}
X
X/*
X * 			C A T C H E R
X * 
X * This routine causes another PING to be transmitted, and then
X * schedules itself to run again 1 second from now.
X * 
X * Bug -
X * 	Our sense of time will slowly skew (ie, packets will not be launched
X * 	exactly at 1-second intervals).  This does not affect the quality
X *	of the delay and loss statistics.
X */
X#ifdef __STDC__
Xstatic void catcher(void)
X#else
Xstatic void catcher()
X#endif
X{
X    int waittime;
X    
X    if (pingSem == NULL)	/* Never been here. */
X      {
X	  pingSem = semBCreate(SEM_Q_FIFO,SEM_EMPTY);
X	  semGive(pingSem);
X	  pingTid = taskSpawn("pinger",100,VX_STDIO,5000,(FUNCPTR)pinger,0,
X                              0,0,0,0,0,0,0,0,0);
X      }
X    else
X      semGive(pingSem);
X    
X    if (npackets == 0 || ntransmitted < npackets)
X      {
X	  (void) wdStart(timer, CLK_TCK * 1, (FUNCPTR)catcher, 0);
X      }
X    else 
X      {
X	  if (nreceived) {
X	      waittime = CLK_TCK * 2 * tmax / 1000;
X	      if (waittime == 0)
X		waittime = CLK_TCK * 1;
X	  } 
X	  else
X	    waittime = MAXWAIT;
X	  (void) wdStart(timer, waittime, (FUNCPTR)die, 0);
X      }
X}
X
X/*
X * 			P I N G E R
X * 
X * Compose and transmit an ICMP ECHO REQUEST packet.  The IP packet
X * will be added on by the kernel.  The ID field is our UNIX process ID,
X * and the sequence number is an ascending integer.  The first 8 bytes
X * of the data portion are used to hold a UNIX "timeval" struct in VAX
X * byte-order, to compute the round-trip time.
X *
X * For VxWorks, run as a task. We wait on a semaphore from catcher
X * saying it's ok to send another packet. Must do this since we cannot
X * do I/O from interrupt state.
X */
X#ifdef __STDC__
Xstatic void pinger(void)
X#else
Xstatic void pinger()
X#endif
X{
X    static u_char outpack[MAXPACKET];
X    register struct icmp *icp = (struct icmp *) outpack;
X    int i, cc;
X    unsigned long int ticks;
X
X    for (;;)
X      {  
X     	  register u_char *datap = &outpack[8+sizeof(unsigned long int)];
X
X	  semTake(pingSem,WAIT_FOREVER);
X
X	  icp->icmp_type = ICMP_ECHO;
X	  icp->icmp_code = 0;
X	  icp->icmp_cksum = 0;
X	  icp->icmp_seq = ntransmitted++;
X	  icp->icmp_id = ident;		/* ID */
X	  
X	  cc = datalen+8;			/* skips ICMP portion */
X
X	  if (timing) {
X	      ticks = tickGet();
X	      bcopy((char *) &ticks, &outpack[8], sizeof(ticks));
X	  }
X	  
X	  for( i=8; i<datalen; i++)	/* skip 8 for time */
X	    *datap++ = i;
X	  
X	  /* Compute ICMP checksum here */
X	  icp->icmp_cksum = in_cksum( (u_short *)icp, cc );
X	  
X	  /* cc = sendto(sfd, msg, len, flags, to, tolen) */
X	  i = sendto( sfd, outpack, cc, 0, &whereto, sizeof(struct sockaddr) );
X	  
X	  if( i < 0 || i != cc )  {
X	      if( i<0 )  perror("sendto");
X	      printf("ping: wrote %s %d chars, ret=%d\n",
X		     hostname, cc, i );
X	      fflush(stdout);
X	  }
X      }
X}
X
X/*
X * 			P R _ T Y P E
X *
X * Convert an ICMP "type" field to a printable string.
X */
X#ifdef __STDC__
Xstatic char *pr_type(FAST int t)
X#else
Xstatic char *pr_type(t)
XFAST int t;
X#endif
X{
X    static char *ttab[] = {
X	"Echo Reply",
X	"ICMP 1",
X	"ICMP 2",
X	"Dest Unreachable",
X	"Source Quence",
X	"Redirect",
X	"ICMP 6",
X	"ICMP 7",
X	"Echo",
X	"ICMP 9",
X	"ICMP 10",
X	"Time Exceeded",
X	"Parameter Problem",
X	"Timestamp",
X	"Timestamp Reply",
X	"Info Request",
X	"Info Reply"
X      };
X    
X    if( t < 0 || t > 16 )
X      return("OUT-OF-RANGE");
X    
X    return(ttab[t]);
X}
X
X/*
X *			P R _ P A C K
X *
X * Print out the packet, if it came from us.  This logic is necessary
X * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
X * which arrive ('tis only fair).  This permits multiple copies of this
X * program to be run without having intermingled output (or statistics!).
X */
X#ifdef __STDC__
Xstatic void pr_pack(FAST char *buf, FAST int cc,
X		    FAST struct sockaddr_in *from )
X#else
Xstatic void pr_pack( buf, cc, from )
Xchar *buf;
Xint cc;
Xstruct sockaddr_in *from;
X#endif
X{
X    struct ip *ip;
X    register struct icmp *icp;
X    register long *lp = (long *) packet;
X    register int i;
X    int hlen, triptime;
X    unsigned long int now,
X    timesent;
X    
X    from->sin_addr.s_addr = ntohl( from->sin_addr.s_addr );
X    now = tickGet();
X    
X    ip = (struct ip *) buf;
X#ifdef PRE51    
X    hlen = ip->ip_hl << 2;
X#else
X    hlen = (ip->ip_v_hl & 0xf) << 2;
X#endif
X    if (cc < hlen + ICMP_MINLEN) {
X	if (verbose)
X	  printf("packet too short (%d bytes) from %s\n", cc,
X		 inet_ntoa(ntohl(from->sin_addr)));
X	return;
X    }
X    cc -= hlen;
X    icp = (struct icmp *)(buf + hlen);
X    if( icp->icmp_type != ICMP_ECHOREPLY )  {
X	if (verbose) {
X	    printf("%d bytes from %s: ", cc,
X		   inet_ntoa(ntohl(from->sin_addr)));
X	    printf("icmp_type=%d (%s)\n",
X		   icp->icmp_type, pr_type(icp->icmp_type) );
X	    for( i=0; i<12; i++)
X	      printf("x%2.2x: x%8.8x\n", i*sizeof(long), *lp++ );
X	    printf("icmp_code=%d\n", icp->icmp_code );
X	}
X	return;
X    }
X    if( icp->icmp_id != ident )
X      return;			/* 'Twas not our ECHO */
X    
X    bcopy(icp->icmp_data, &timesent, sizeof(timesent));
X    printf("%d bytes from %s: ", cc,
X	   inet_ntoa(ntohl(from->sin_addr)));
X    printf("icmp_seq=%d. ", icp->icmp_seq );
X    if (timing) {
X	triptime = (now - timesent) * (1000 / CLK_TCK);
X	printf("time=%d. ms\n", triptime );
X	tsum += triptime;
X	if( triptime < tmin )
X	  tmin = triptime;
X	if( triptime > tmax )
X	  tmax = triptime;
X    } else
X      putchar('\n');
X    nreceived++;
X}
X
X
X/*
X *			I N _ C K S U M
X *
X * Checksum routine for Internet Protocol family headers (C Version)
X *
X */
X#ifdef __STDC__
Xstatic in_cksum(u_short *addr, int len)
X#else
Xstatic in_cksum(addr, len)
Xu_short *addr;
Xint len;
X#endif
X{
X    register int nleft = len;
X    register u_short *w = addr;
X    register u_short answer;
X    register int sum = 0;
X    u_short odd_byte = 0;
X    
X    /*
X     *  Our algorithm is simple, using a 32 bit accumulator (sum),
X     *  we add sequential 16 bit words to it, and at the end, fold
X     *  back all the carry bits from the top 16 bits into the lower
X     *  16 bits.
X     */
X    while( nleft > 1 )  {
X	sum += *w++;
X	nleft -= 2;
X    }
X    
X    /* mop up an odd byte, if necessary */
X    if( nleft == 1 ) {
X	*(u_char *)(&odd_byte) = *(u_char *)w;
X	sum += odd_byte;
X    }
X    
X    /*
X     * add back carry outs from top 16 bits to low 16 bits
X     */
X    sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
X    sum += (sum >> 16);			/* add carry */
X    answer = ~sum;				/* truncate to 16 bits */
X    return (answer);
X}
X
X/*
X *			F I N I S H
X *
X * Print out statistics, and give up.
X * Heavily buffered STDIO is used here, so that all the statistics
X * will be written with 1 sys-write call.  This is nice when more
X * than one copy of the program is running on a terminal;  it prevents
X * the statistics output from becomming intermingled.
X */
X#ifdef __STDC__
Xvoid static finish(void)
X#else
Xvoid static finish()
X#endif
X{
X    (void) taskDeleteHookDelete(finish);
X    wdDelete(timer);
X    taskDelete(pingTid);	/* Must kill the pinger. */
X    semDelete(pingSem);
X    pingSem = NULL;
X    printf("\n----%s PING Statistics----\n", hostname );
X    printf("%d packets transmitted, ", ntransmitted );
X    printf("%d packets received, ", nreceived );
X    if (ntransmitted)
X      printf("%d%% packet loss",
X	     (int) (((ntransmitted-nreceived)*100) / ntransmitted ) );
X    printf("\n");
X    if (nreceived && timing)
X      printf("round-trip (ms)  min/avg/max = %d/%d/%d\n",
X	     tmin,
X	     tsum / nreceived,
X	     tmax );
X    fflush(stdout);
X    (void) close(sfd);
X}
X
X/*
X *                      DIE
X *
X *  Die causes termination and printing of the summary by killing the main
X *  task. It will only be called if the entry point is pingn.
X */
X
X#ifdef __STDC__
Xstatic void die(void)
X#else
Xstatic void die()
X#endif
X{
X    taskDelete(mainTid);
X}
END_OF_FILE
if test 15418 -ne `wc -c <'ping/ping.c'`; then
    echo shar: \"'ping/ping.c'\" unpacked with wrong size!
fi
# end of 'ping/ping.c'
fi
echo shar: End of archive 1 \(of 1\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have the archive.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
