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

📄 bsdping.c

📁 unix网络编程第一卷socket编程书上的全部源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*	BSDI	ping.c,v 2.3 1996/01/21 17:56:50 jch Exp	*//* * 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 *//* * 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/time.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 <arpa/inet.h>#include <netdb.h>#include <ctype.h>#include <err.h>#include <errno.h>#include <fcntl.h>#include <signal.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#define	DEFDATALEN	(64 - 8)	/* default data length */#define	MAXIPLEN	60#define	MAXICMPLEN	76#define	MAXPACKET	(65536 - 60 - 8)/* max packet size */#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))#define	F_FLOOD		0x0001#define	F_INTERVAL	0x0002#define	F_NUMERIC	0x0004#define	F_PINGFILLED	0x0008#define	F_QUIET		0x0010#define	F_RROUTE	0x0020#define	F_SO_DEBUG	0x0040#define	F_SO_DONTROUTE	0x0080#define	F_VERBOSE	0x0100u_int options;/* * 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 * 8192)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 */void	 fill __P((char *, char *));u_short	 in_cksum __P((u_short *, int));void	 onalrm __P((int));void	 oninfo __P((int));void	 onint __P((int));void	 pinger __P((void));char	*pr_addr __P((u_long));void	 pr_icmph __P((struct icmp *));void	 pr_iph __P((struct ip *));void	 pr_pack __P((char *, int, struct sockaddr_in *));void	 pr_retip __P((struct ip *));void	 summary __P((void));void	 tvsub __P((struct timeval *, struct timeval *));void	 usage __P((void));intmain(argc, argv)	int argc;	char *argv[];{	extern int errno, optind;	extern char *optarg;	struct hostent *hp;	struct itimerval itimer;	struct protoent *proto;	struct sockaddr_in *to, from;	struct timeval timeout;	fd_set fdset;	register int cc, i;	int ch, fromlen, hold, packlen, preload;	u_char *datap, *packet;	char *e, *target, hnamebuf[MAXHOSTNAMELEN];#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, "c:dfi:l:np:qRrs:v")) != -1)		switch(ch) {		case 'c':			npackets = strtol(optarg, &e, 10);			if (npackets <= 0 || *optarg == '\0' || *e != '\0')				errx(1,				    "illegal number of packets -- %s", optarg);			break;		case 'd':			options |= F_SO_DEBUG;			break;		case 'f':			if (getuid()) {				errno = EPERM;				err(1, NULL);			}			options |= F_FLOOD;			setbuf(stdout, (char *)NULL);			break;		case 'i':		/* wait between sending packets */			interval = strtol(optarg, &e, 10);			if (interval <= 0 || *optarg == '\0' || *e != '\0')				errx(1,				    "illegal timing interval -- %s", optarg);			options |= F_INTERVAL;			break;		case 'l':			preload = strtol(optarg, &e, 10);			if (preload < 0 || *optarg == '\0' || *e != '\0')				errx(1, "illegal preload value -- %s", optarg);			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 = strtol(optarg, &e, 10);			if (datalen <= 0 || *optarg == '\0' || *e != '\0')				errx(1, "illegal datalen value -- %s", optarg);			if (datalen > MAXPACKET)				errx(1,				    "datalen value too large, maximum is %d",				    MAXPACKET);			break;		case 'v':			options |= F_VERBOSE;			break;		default:			usage();		}	argc -= optind;	argv += optind;	if (argc != 1)		usage();	target = *argv;	memset(&whereto, 0, 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)			errx(1, "unknown host %s", target);		to->sin_family = hp->h_addrtype;		memmove(&to->sin_addr, hp->h_addr, hp->h_length);		(void)strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf) - 1);		hostname = hnamebuf;	}	if (options & F_FLOOD && options & F_INTERVAL)		errx(1, "-f and -i incompatible options");	if (datalen >= sizeof(struct timeval))	/* can we time transfer */		timing = 1;	packlen = datalen + MAXIPLEN + MAXICMPLEN;	if (!(packet = (u_char *)malloc((u_int)packlen)))		err(1, NULL);	if (!(options & F_PINGFILLED))		for (i = 8; i < datalen; ++i)			*datap++ = i;	ident = getpid() & 0xFFFF;	if (!(proto = getprotobyname("icmp")))		errx(1, "unknown protocol icmp");	if ((s = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0)		err(1, "socket");	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)			err(1, "record route");#else		errx(1, "record route not available in this implementation");#endif	}	/*	 * 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);	while (preload--)		/* Fire off them quickies. */		pinger();	(void)signal(SIGINT, onint);	(void)signal(SIGINFO, oninfo);	if ((options & F_FLOOD) == 0) {		(void)signal(SIGALRM, onalrm);		itimer.it_interval.tv_sec = interval;		itimer.it_interval.tv_usec = 0;		itimer.it_value.tv_sec = 0;		itimer.it_value.tv_usec = 1;		(void)setitimer(ITIMER_REAL, &itimer, NULL);	}	FD_ZERO(&fdset);	timeout.tv_sec = 0;	timeout.tv_usec = 10000;	for (;;) {		if (options & F_FLOOD) {			pinger();			FD_SET(s, &fdset);			if (select(s + 1, &fdset, NULL, NULL, &timeout) < 1)				continue;		}		fromlen = sizeof(from);		if ((cc = recvfrom(s, (char *)packet, packlen, 0,		    (struct sockaddr *)&from, &fromlen)) < 0) {			if (errno == EINTR)				continue;			warn("recvfrom");			continue;		}		pr_pack((char *)packet, cc, &from);		if (npackets && nreceived >= npackets)			break;	}	summary();	exit(nreceived == 0);}/* * onalrm -- *	This routine transmits another ping. */voidonalrm(signo)	int signo;{	struct itimerval itimer;	if (!npackets || ntransmitted < npackets) {		pinger();		return;	}	/*	 * If we're not transmitting any more packets, change the timer	 * to wait two round-trip times if we've received any packets or	 * ten seconds if we haven't.	 */#define	MAXWAIT		10	if (nreceived) {		itimer.it_value.tv_sec =  2 * tmax / 1000;		if (itimer.it_value.tv_sec == 0)			itimer.it_value.tv_sec = 1;	} else		itimer.it_value.tv_sec = MAXWAIT;	itimer.it_interval.tv_sec = 0;	itimer.it_interval.tv_usec = 0;	itimer.it_value.tv_usec = 0;	(void)signal(SIGALRM, onint);	(void)setitimer(ITIMER_REAL, &itimer, NULL);}/* * 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. */voidpinger(){	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], 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)			warn("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!). */voidpr_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, NULL);	/* Check the IP header */	ip = (struct ip *)buf;	hlen = ip->ip_hl << 2;	if (cc < hlen + ICMP_MINLEN) {		if (options & F_VERBOSE)			warnx("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;#endif			tvsub(&tv, tp);			triptime = ((double)tv.tv_sec) * 1000.0 +			    ((double)tv.tv_usec) / 1000.0;			tsum += triptime;			if (triptime < tmin)				tmin = triptime;			if (triptime > tmax)				tmax = triptime;		}		if (TST(icp->icmp_seq % mx_dup_ck)) {			++nrepeats;			--nreceived;			dupflag = 1;		} else {

⌨️ 快捷键说明

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