⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ping.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 1989, 1993 *	The Regents of the University of California.  All rights reserved. * * This code is derived from software contributed to Berkeley by * Mike Muuss. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char copyright[] ="@(#) Copyright (c) 1989, 1993\n\	The Regents of the University of California.  All rights reserved.\n";#endif /* not lint */#ifndef lintstatic char sccsid[] = "@(#)ping.c	8.1 (Berkeley) 6/5/93";#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 * * 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. */#include <sys/param.h>#include <sys/socket.h>#include <sys/file.h>#include <sys/time.h>#include <sys/signal.h>#include <netinet/in_systm.h>#include <netinet/in.h>#include <netinet/ip.h>#include <netinet/ip_icmp.h>#include <netinet/ip_var.h>#include <netdb.h>#include <unistd.h>#include <stdio.h>#include <ctype.h>#include <errno.h>#include <string.h>#define	DEFDATALEN	(64 - 8)	/* default data length */#define	MAXIPLEN	60#define	MAXICMPLEN	76#define	MAXPACKET	(65536 - 60 - 8)/* max packet size */#define	MAXWAIT		10		/* max seconds to wait for response */#define	NROUTES		9		/* number of record route slots */#define	A(bit)		rcvd_tbl[(bit)>>3]	/* identify byte in array */#define	B(bit)		(1 << ((bit) & 0x07))	/* identify bit in byte */#define	SET(bit)	(A(bit) |= B(bit))#define	CLR(bit)	(A(bit) &= (~B(bit)))#define	TST(bit)	(A(bit) & B(bit))/* various options */int options;#define	F_FLOOD		0x001#define	F_INTERVAL	0x002#define	F_NUMERIC	0x004#define	F_PINGFILLED	0x008#define	F_QUIET		0x010#define	F_RROUTE	0x020#define	F_SO_DEBUG	0x040#define	F_SO_DONTROUTE	0x080#define	F_VERBOSE	0x100/* * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum * number of received sequence numbers we can keep track of.  Change 128 * to 8192 for complete accuracy... */#define	MAX_DUP_CHK	(8 * 128)int mx_dup_ck = MAX_DUP_CHK;char rcvd_tbl[MAX_DUP_CHK / 8];struct sockaddr whereto;	/* who to ping */int datalen = DEFDATALEN;int s;				/* socket file descriptor */u_char outpack[MAXPACKET];char BSPACE = '\b';		/* characters written for flood */char DOT = '.';char *hostname;int ident;			/* process id to identify our packets *//* counters */long npackets;			/* max packets to transmit */long nreceived;			/* # of packets we got back */long nrepeats;			/* number of duplicates */long ntransmitted;		/* sequence # for outbound packets = #sent */int interval = 1;		/* interval between packets *//* timing */int timing;			/* flag to do timing */double tmin = 999999999.0;	/* minimum round trip time */double tmax = 0.0;		/* maximum round trip time */double tsum = 0.0;		/* sum of all times, for doing average */char *pr_addr();void catcher(), finish();main(argc, argv)	int argc;	char **argv;{	extern int errno, optind;	extern char *optarg;	struct timeval timeout;	struct hostent *hp;	struct sockaddr_in *to;	struct protoent *proto;	register int i;	int ch, fdmask, hold, packlen, preload;	u_char *datap, *packet;	char *target, hnamebuf[MAXHOSTNAMELEN], *malloc();#ifdef IP_OPTIONS	char rspace[3 + 4 * NROUTES + 1];	/* record route space */#endif	preload = 0;	datap = &outpack[8 + sizeof(struct timeval)];	while ((ch = getopt(argc, argv, "Rc:dfh:i:l:np:qrs:v")) != EOF)		switch(ch) {		case 'c':			npackets = atoi(optarg);			if (npackets <= 0) {				(void)fprintf(stderr,				    "ping: bad number of packets to transmit.\n");				exit(1);			}			break;		case 'd':			options |= F_SO_DEBUG;			break;		case 'f':			if (getuid()) {				(void)fprintf(stderr,				    "ping: %s\n", strerror(EPERM));				exit(1);			}			options |= F_FLOOD;			setbuf(stdout, (char *)NULL);			break;		case 'i':		/* wait between sending packets */			interval = atoi(optarg);			if (interval <= 0) {				(void)fprintf(stderr,				    "ping: bad timing interval.\n");				exit(1);			}			options |= F_INTERVAL;			break;		case 'l':			preload = atoi(optarg);			if (preload < 0) {				(void)fprintf(stderr,				    "ping: bad preload value.\n");				exit(1);			}			break;		case 'n':			options |= F_NUMERIC;			break;		case 'p':		/* fill buffer with user pattern */			options |= F_PINGFILLED;			fill((char *)datap, optarg);				break;		case 'q':			options |= F_QUIET;			break;		case 'R':			options |= F_RROUTE;			break;		case 'r':			options |= F_SO_DONTROUTE;			break;		case 's':		/* size of packet to send */			datalen = atoi(optarg);			if (datalen > MAXPACKET) {				(void)fprintf(stderr,				    "ping: packet size too large.\n");				exit(1);			}			if (datalen <= 0) {				(void)fprintf(stderr,				    "ping: illegal packet size.\n");				exit(1);			}			break;		case 'v':			options |= F_VERBOSE;			break;		default:			usage();		}	argc -= optind;	argv += optind;	if (argc != 1)		usage();	target = *argv;	bzero((char *)&whereto, sizeof(struct sockaddr));	to = (struct sockaddr_in *)&whereto;	to->sin_family = AF_INET;	to->sin_addr.s_addr = inet_addr(target);	if (to->sin_addr.s_addr != (u_int)-1)		hostname = target;	else {		hp = gethostbyname(target);		if (!hp) {			(void)fprintf(stderr,			    "ping: unknown host %s\n", target);			exit(1);		}		to->sin_family = hp->h_addrtype;		bcopy(hp->h_addr, (caddr_t)&to->sin_addr, hp->h_length);		(void)strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf) - 1);		hostname = hnamebuf;	}	if (options & F_FLOOD && options & F_INTERVAL) {		(void)fprintf(stderr,		    "ping: -f and -i incompatible options.\n");		exit(1);	}	if (datalen >= sizeof(struct timeval))	/* can we time transfer */		timing = 1;	packlen = datalen + MAXIPLEN + MAXICMPLEN;	if (!(packet = (u_char *)malloc((u_int)packlen))) {		(void)fprintf(stderr, "ping: out of memory.\n");		exit(1);	}	if (!(options & F_PINGFILLED))		for (i = 8; i < datalen; ++i)			*datap++ = i;	ident = getpid() & 0xFFFF;	if (!(proto = getprotobyname("icmp"))) {		(void)fprintf(stderr, "ping: unknown protocol icmp.\n");		exit(1);	}	if ((s = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0) {		perror("ping: socket");		exit(1);	}	hold = 1;	if (options & F_SO_DEBUG)		(void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold,		    sizeof(hold));	if (options & F_SO_DONTROUTE)		(void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&hold,		    sizeof(hold));	/* record route option */	if (options & F_RROUTE) {#ifdef IP_OPTIONS		rspace[IPOPT_OPTVAL] = IPOPT_RR;		rspace[IPOPT_OLEN] = sizeof(rspace)-1;		rspace[IPOPT_OFFSET] = IPOPT_MINOFF;		if (setsockopt(s, IPPROTO_IP, IP_OPTIONS, rspace,		    sizeof(rspace)) < 0) {			perror("ping: record route");			exit(1);		}#else		(void)fprintf(stderr,		  "ping: record route not available in this implementation.\n");		exit(1);#endif /* IP_OPTIONS */	}	/*	 * When pinging the broadcast address, you can get a lot of answers.	 * Doing something so evil is useful if you are trying to stress the	 * ethernet, or just want to fill the arp cache to get some stuff for	 * /etc/ethers.	 */	hold = 48 * 1024;	(void)setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold,	    sizeof(hold));	if (to->sin_family == AF_INET)		(void)printf("PING %s (%s): %d data bytes\n", hostname,		    inet_ntoa(*(struct in_addr *)&to->sin_addr.s_addr),		    datalen);	else		(void)printf("PING %s: %d data bytes\n", hostname, datalen);	(void)signal(SIGINT, finish);	(void)signal(SIGALRM, catcher);	while (preload--)		/* fire off them quickies */		pinger();	if ((options & F_FLOOD) == 0)		catcher();		/* start things going */	for (;;) {		struct sockaddr_in from;		register int cc;		int fromlen;		if (options & F_FLOOD) {			pinger();			timeout.tv_sec = 0;			timeout.tv_usec = 10000;			fdmask = 1 << s;			if (select(s + 1, (fd_set *)&fdmask, (fd_set *)NULL,			    (fd_set *)NULL, &timeout) < 1)				continue;		}		fromlen = sizeof(from);		if ((cc = recvfrom(s, (char *)packet, packlen, 0,		    (struct sockaddr *)&from, &fromlen)) < 0) {			if (errno == EINTR)				continue;			perror("ping: recvfrom");			continue;		}		pr_pack((char *)packet, cc, &from);		if (npackets && nreceived >= npackets)			break;	}	finish();	/* NOTREACHED */}/* * catcher -- *	This routine causes another PING to be transmitted, and then * schedules another SIGALRM for 1 second from now. * * bug -- *	Our sense of time will slowly skew (i.e., packets will not be * launched exactly at 1-second intervals).  This does not affect the * quality of the delay and loss statistics. */voidcatcher(){	int waittime;	pinger();	(void)signal(SIGALRM, catcher);	if (!npackets || ntransmitted < npackets)		alarm((u_int)interval);	else {		if (nreceived) {			waittime = 2 * tmax / 1000;			if (!waittime)				waittime = 1;		} else			waittime = MAXWAIT;		(void)signal(SIGALRM, finish);		(void)alarm((u_int)waittime);	}}/* * pinger -- *	Compose and transmit an ICMP ECHO REQUEST packet.  The IP packet * will be added on by the kernel.  The ID field is our UNIX process ID, * and the sequence number is an ascending integer.  The first 8 bytes * of the data portion are used to hold a UNIX "timeval" struct in VAX * byte-order, to compute the round-trip time. */pinger(){	register struct icmp *icp;	register int cc;	int i;	icp = (struct icmp *)outpack;	icp->icmp_type = ICMP_ECHO;	icp->icmp_code = 0;	icp->icmp_cksum = 0;	icp->icmp_seq = ntransmitted++;	icp->icmp_id = ident;			/* ID */	CLR(icp->icmp_seq % mx_dup_ck);	if (timing)		(void)gettimeofday((struct timeval *)&outpack[8],		    (struct timezone *)NULL);	cc = datalen + 8;			/* skips ICMP portion */	/* compute ICMP checksum here */	icp->icmp_cksum = in_cksum((u_short *)icp, cc);	i = sendto(s, (char *)outpack, cc, 0, &whereto,	    sizeof(struct sockaddr));	if (i < 0 || i != cc)  {		if (i < 0)			perror("ping: sendto");		(void)printf("ping: wrote %s %d chars, ret=%d\n",		    hostname, cc, i);	}	if (!(options & F_QUIET) && options & F_FLOOD)		(void)write(STDOUT_FILENO, &DOT, 1);}/* * pr_pack -- *	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;	int cc;	struct sockaddr_in *from;{	register struct icmp *icp;	register u_long l;	register int i, j;	register u_char *cp,*dp;	static int old_rrlen;	static char old_rr[MAX_IPOPTLEN];	struct ip *ip;	struct timeval tv, *tp;	double triptime;	int hlen, dupflag;	(void)gettimeofday(&tv, (struct timezone *)NULL);	/* Check the IP header */	ip = (struct ip *)buf;	hlen = ip->ip_hl << 2;	if (cc < hlen + ICMP_MINLEN) {		if (options & F_VERBOSE)			(void)fprintf(stderr,			  "ping: packet too short (%d bytes) from %s\n", cc,			  inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr));		return;	}	/* Now the ICMP part */	cc -= hlen;	icp = (struct icmp *)(buf + hlen);	if (icp->icmp_type == ICMP_ECHOREPLY) {		if (icp->icmp_id != ident)			return;			/* 'Twas not our ECHO */		++nreceived;		if (timing) {#ifndef icmp_data			tp = (struct timeval *)&icp->icmp_ip;#else			tp = (struct timeval *)icp->icmp_data;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -