#! /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 '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 X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include X X#ifdef PRE_51 X#include X#include X#include X#else X#include X#include X#include 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; iicmp_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, ×ent, 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