Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 20 Sep 2014 19:54:19 +0000 (UTC)
From:      Hiroki Sato <hrs@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r271910 - head/sbin/ping6
Message-ID:  <201409201954.s8KJsJnE086075@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: hrs
Date: Sat Sep 20 19:54:19 2014
New Revision: 271910
URL: http://svnweb.freebsd.org/changeset/base/271910

Log:
  Fix a problem that reply packets are not received when -i T option is set
  and (T < RTT).
  
  - Use select(2) for timeout instead of interval timer. Remove poll(2) support.
  - Use sigaction(2) instead of signal(3).
  - Exit in SIGINT handler when two signals are received and doing reverse DNS
    lookup as ping(8) does.
  - Remove redundant variables used for getaddrinfo(3).
  
  PR:	151023

Modified:
  head/sbin/ping6/Makefile
  head/sbin/ping6/ping6.c

Modified: head/sbin/ping6/Makefile
==============================================================================
--- head/sbin/ping6/Makefile	Sat Sep 20 18:48:50 2014	(r271909)
+++ head/sbin/ping6/Makefile	Sat Sep 20 19:54:19 2014	(r271910)
@@ -4,7 +4,7 @@ PROG=	ping6
 MAN=	ping6.8
 
 CFLAGS+=-DIPSEC -DKAME_SCOPEID -DUSE_RFC2292BIS \
-	-DHAVE_POLL_H -DHAVE_ARC4RANDOM
+	-DHAVE_ARC4RANDOM
 WARNS?=	2
 
 BINOWN=	root

Modified: head/sbin/ping6/ping6.c
==============================================================================
--- head/sbin/ping6/ping6.c	Sat Sep 20 18:48:50 2014	(r271909)
+++ head/sbin/ping6/ping6.c	Sat Sep 20 19:54:19 2014	(r271910)
@@ -125,10 +125,8 @@ __FBSDID("$FreeBSD$");
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sysexits.h>
 #include <unistd.h>
-#ifdef HAVE_POLL_H
-#include <poll.h>
-#endif
 
 #ifdef IPSEC
 #include <netipsec/ah.h>
@@ -207,7 +205,6 @@ u_int options;
 int mx_dup_ck = MAX_DUP_CHK;
 char rcvd_tbl[MAX_DUP_CHK / 8];
 
-struct addrinfo *res = NULL;
 struct sockaddr_in6 dst;	/* who to ping6 */
 struct sockaddr_in6 src;	/* src addr of this packet */
 socklen_t srclen;
@@ -223,12 +220,6 @@ u_int8_t nonce[8];		/* nonce field for n
 int hoplimit = -1;		/* hoplimit */
 int pathmtu = 0;		/* path MTU for the destination.  0 = unspec. */
 u_char *packet = NULL;
-#ifdef HAVE_POLL_H
-struct pollfd fdmaskp[1];
-#else
-fd_set *fdmaskp = NULL;
-int fdmasks;
-#endif
 
 /* counters */
 long nmissedmax;		/* max value of ntransmitted - nreceived - 1 */
@@ -236,7 +227,7 @@ long npackets;			/* max packets to trans
 long nreceived;			/* # of packets we got back */
 long nrepeats;			/* number of duplicates */
 long ntransmitted;		/* sequence # for outbound packets = #sent */
-struct timeval interval = {1, 0}; /* interval between packets */
+int interval = 1000;		/* interval between packets in ms */
 
 /* timing */
 int timing;			/* flag to do timing */
@@ -253,7 +244,6 @@ struct msghdr smsghdr;
 struct iovec smsgiov;
 char *scmsg = 0;
 
-volatile sig_atomic_t seenalrm;
 volatile sig_atomic_t seenint;
 #ifdef SIGINFO
 volatile sig_atomic_t seeninfo;
@@ -265,7 +255,6 @@ int	 get_hoplim(struct msghdr *);
 int	 get_pathmtu(struct msghdr *);
 struct in6_pktinfo *get_rcvpktinfo(struct msghdr *);
 void	 onsignal(int);
-void	 retransmit(void);
 void	 onint(int);
 size_t	 pingerlen(void);
 int	 pinger(void);
@@ -293,19 +282,15 @@ void	 usage(void);
 int
 main(int argc, char *argv[])
 {
-	struct itimerval itimer;
-	struct sockaddr_in6 from;
+	struct timeval last, intvl;
+	struct sockaddr_in6 from, *sin6;
 #ifndef HAVE_ARC4RANDOM
 	struct timeval seed;
 #endif
-#ifdef HAVE_POLL_H
-	int timeout;
-#else
-	struct timeval timeout, *tv;
-#endif
-	struct addrinfo hints;
+	struct addrinfo hints, *res;
+	struct sigaction si_sa;
 	int cc, i;
-	int ch, hold, packlen, preload, optval, ret_ga;
+	int almost_done, ch, hold, packlen, preload, optval, error;
 	int nig_oldmcprefix = -1;
 	u_char *datap;
 	char *e, *target, *ifname = NULL, *gateway = NULL;
@@ -326,7 +311,7 @@ main(int argc, char *argv[])
 	char *policy_in = NULL;
 	char *policy_out = NULL;
 #endif
-	double intval;
+	double t;
 	size_t rthlen;
 #ifdef IPV6_USE_MIN_MTU
 	int mflag = 0;
@@ -450,22 +435,22 @@ main(int argc, char *argv[])
 #endif
 			break;
 		case 'i':		/* wait between sending packets */
-			intval = strtod(optarg, &e);
+			t = strtod(optarg, &e);
 			if (*optarg == '\0' || *e != '\0')
 				errx(1, "illegal timing interval %s", optarg);
-			if (intval < 1 && getuid()) {
+			if (t < 1 && getuid()) {
 				errx(1, "%s: only root may use interval < 1s",
 				    strerror(EPERM));
 			}
-			interval.tv_sec = (long)intval;
-			interval.tv_usec =
-			    (long)((intval - interval.tv_sec) * 1000000);
-			if (interval.tv_sec < 0)
+			intvl.tv_sec = (long)t;
+			intvl.tv_usec =
+			    (long)((t - intvl.tv_sec) * 1000000);
+			if (intvl.tv_sec < 0)
 				errx(1, "illegal timing interval %s", optarg);
 			/* less than 1/hz does not make sense */
-			if (interval.tv_sec == 0 && interval.tv_usec < 1) {
+			if (intvl.tv_sec == 0 && intvl.tv_usec < 1) {
 				warnx("too small interval, raised to .000001");
-				interval.tv_usec = 1;
+				intvl.tv_usec = 1;
 			}
 			options |= F_INTERVAL;
 			break;
@@ -516,10 +501,10 @@ main(int argc, char *argv[])
 			hints.ai_socktype = SOCK_RAW;
 			hints.ai_protocol = IPPROTO_ICMPV6;
 
-			ret_ga = getaddrinfo(optarg, NULL, &hints, &res);
-			if (ret_ga) {
+			error = getaddrinfo(optarg, NULL, &hints, &res);
+			if (error) {
 				errx(1, "invalid source address: %s",
-				     gai_strerror(ret_ga));
+				     gai_strerror(error));
 			}
 			/*
 			 * res->ai_family must be AF_INET6 and res->ai_addrlen
@@ -622,9 +607,9 @@ main(int argc, char *argv[])
 	hints.ai_socktype = SOCK_RAW;
 	hints.ai_protocol = IPPROTO_ICMPV6;
 
-	ret_ga = getaddrinfo(target, NULL, &hints, &res);
-	if (ret_ga)
-		errx(1, "%s", gai_strerror(ret_ga));
+	error = getaddrinfo(target, NULL, &hints, &res);
+	if (error)
+		errx(1, "%s", gai_strerror(error));
 	if (res->ai_canonname)
 		hostname = res->ai_canonname;
 	else
@@ -647,28 +632,25 @@ main(int argc, char *argv[])
 
 	/* set the gateway (next hop) if specified */
 	if (gateway) {
-		struct addrinfo ghints, *gres;
-		int error;
-
-		memset(&ghints, 0, sizeof(ghints));
-		ghints.ai_family = AF_INET6;
-		ghints.ai_socktype = SOCK_RAW;
-		ghints.ai_protocol = IPPROTO_ICMPV6;
+		memset(&hints, 0, sizeof(hints));
+		hints.ai_family = AF_INET6;
+		hints.ai_socktype = SOCK_RAW;
+		hints.ai_protocol = IPPROTO_ICMPV6;
 
-		error = getaddrinfo(gateway, NULL, &hints, &gres);
+		error = getaddrinfo(gateway, NULL, &hints, &res);
 		if (error) {
 			errx(1, "getaddrinfo for the gateway %s: %s",
 			     gateway, gai_strerror(error));
 		}
-		if (gres->ai_next && (options & F_VERBOSE))
+		if (res->ai_next && (options & F_VERBOSE))
 			warnx("gateway resolves to multiple addresses");
 
 		if (setsockopt(s, IPPROTO_IPV6, IPV6_NEXTHOP,
-			       gres->ai_addr, gres->ai_addrlen)) {
+		    res->ai_addr, res->ai_addrlen)) {
 			err(1, "setsockopt(IPV6_NEXTHOP)");
 		}
 
-		freeaddrinfo(gres);
+		freeaddrinfo(res);
 	}
 
 	/*
@@ -898,7 +880,7 @@ main(int argc, char *argv[])
 	}
 
 	if (argc > 1) {	/* some intermediate addrs are specified */
-		int hops, error;
+		int hops;
 #ifdef USE_RFC2292BIS
 		int rthdrlen;
 #endif
@@ -920,26 +902,25 @@ main(int argc, char *argv[])
 #endif /* USE_RFC2292BIS */
 
 		for (hops = 0; hops < argc - 1; hops++) {
-			struct addrinfo *iaip;
+			memset(&hints, 0, sizeof(hints));
+			hints.ai_family = AF_INET6;
 
 			if ((error = getaddrinfo(argv[hops], NULL, &hints,
-			    &iaip)))
+			    &res)))
 				errx(1, "%s", gai_strerror(error));
-			if (SIN6(iaip->ai_addr)->sin6_family != AF_INET6)
+			if (res->ai_addr->sa_family != AF_INET6)
 				errx(1,
 				    "bad addr family of an intermediate addr");
-
+			sin6 = (struct sockaddr_in6 *)(void *)res->ai_addr;
 #ifdef USE_RFC2292BIS
-			if (inet6_rth_add(rthdr,
-			    &(SIN6(iaip->ai_addr))->sin6_addr))
+			if (inet6_rth_add(rthdr, &sin6->sin6_addr))
 				errx(1, "can't add an intermediate node");
 #else  /* old advanced API */
-			if (inet6_rthdr_add(scmsgp,
-			    &(SIN6(iaip->ai_addr))->sin6_addr,
+			if (inet6_rthdr_add(scmsg, &sin6->sin6_addr,
 			    IPV6_RTHDR_LOOSE))
 				errx(1, "can't add an intermediate node");
 #endif /* USE_RFC2292BIS */
-			freeaddrinfo(iaip);
+			freeaddrinfo(res);
 		}
 
 #ifndef USE_RFC2292BIS
@@ -1055,52 +1036,46 @@ main(int argc, char *argv[])
 	printf("%s --> ", pr_addr((struct sockaddr *)&src, sizeof(src)));
 	printf("%s\n", pr_addr((struct sockaddr *)&dst, sizeof(dst)));
 
-	while (preload--)		/* Fire off them quickies. */
-		(void)pinger();
-
-	(void)signal(SIGINT, onsignal);
-#ifdef SIGINFO
-	(void)signal(SIGINFO, onsignal);
-#endif
-
-	if ((options & F_FLOOD) == 0) {
-		(void)signal(SIGALRM, onsignal);
-		itimer.it_interval = interval;
-		itimer.it_value = interval;
-		(void)setitimer(ITIMER_REAL, &itimer, NULL);
-		if (ntransmitted == 0)
-			retransmit();
-	}
-
-#ifndef HAVE_POLL_H
-	fdmasks = howmany(s + 1, NFDBITS) * sizeof(fd_mask);
-	if ((fdmaskp = malloc(fdmasks)) == NULL)
-		err(1, "malloc");
-#endif
-
-	seenalrm = seenint = 0;
+	if (preload == 0)
+		pinger();
+	else {
+		if (npackets != 0 && preload > npackets)
+			preload = npackets;
+		while (preload--)
+			pinger();
+	}
+	gettimeofday(&last, NULL);
+
+	sigemptyset(&si_sa.sa_mask);
+	si_sa.sa_flags = 0;
+	si_sa.sa_handler = onsignal;
+	if (sigaction(SIGINT, &si_sa, 0) == -1)
+		err(EX_OSERR, "sigaction SIGINT");
+	seenint = 0;
 #ifdef SIGINFO
+	if (sigaction(SIGINFO, &si_sa, 0) == -1)
+		err(EX_OSERR, "sigaction SIGINFO");
 	seeninfo = 0;
 #endif
+	if (options & F_FLOOD) {
+		intvl.tv_sec = 0;
+		intvl.tv_usec = 10000;
+	} else if ((options & F_INTERVAL) == 0) {
+		intvl.tv_sec = interval / 1000;
+		intvl.tv_usec = interval % 1000 * 1000;
+	}
 
-	for (;;) {
+	almost_done = 0;
+	while (seenint == 0) {
+		struct timeval now, timeout;
 		struct msghdr m;
 		struct iovec iov[2];
+		fd_set rfds;
+		int n;
 
 		/* signal handling */
-		if (seenalrm) {
-			/* last packet sent, timeout reached? */
-			if (npackets && ntransmitted >= npackets)
-				break;
-			retransmit();
-			seenalrm = 0;
-			continue;
-		}
-		if (seenint) {
+		if (seenint)
 			onint(SIGINT);
-			seenint = 0;
-			continue;
-		}
 #ifdef SIGINFO
 		if (seeninfo) {
 			summary();
@@ -1108,93 +1083,104 @@ main(int argc, char *argv[])
 			continue;
 		}
 #endif
+		FD_ZERO(&rfds);
+		FD_SET(s, &rfds);
+		gettimeofday(&now, NULL);
+		timeout.tv_sec = last.tv_sec + intvl.tv_sec - now.tv_sec;
+		timeout.tv_usec = last.tv_usec + intvl.tv_usec - now.tv_usec;
+		while (timeout.tv_usec < 0) {
+			timeout.tv_usec += 1000000;
+			timeout.tv_sec--;
+		}
+		while (timeout.tv_usec > 1000000) {
+			timeout.tv_usec -= 1000000;
+			timeout.tv_sec++;
+		}
+		if (timeout.tv_sec < 0)
+			timeout.tv_sec = timeout.tv_usec = 0;
+
+		n = select(s + 1, &rfds, NULL, NULL, &timeout);
+		if (n < 0)
+			continue;	/* EINTR */
+		if (n == 1) {
+			m.msg_name = (caddr_t)&from;
+			m.msg_namelen = sizeof(from);
+			memset(&iov, 0, sizeof(iov));
+			iov[0].iov_base = (caddr_t)packet;
+			iov[0].iov_len = packlen;
+			m.msg_iov = iov;
+			m.msg_iovlen = 1;
+			memset(cm, 0, CONTROLLEN);
+			m.msg_control = (void *)cm;
+			m.msg_controllen = CONTROLLEN;
+
+			cc = recvmsg(s, &m, 0);
+			if (cc < 0) {
+				if (errno != EINTR) {
+					warn("recvmsg");
+					sleep(1);
+				}
+				continue;
+			} else if (cc == 0) {
+				int mtu;
 
-		if (options & F_FLOOD) {
-			(void)pinger();
-#ifdef HAVE_POLL_H
-			timeout = 10;
-#else
-			timeout.tv_sec = 0;
-			timeout.tv_usec = 10000;
-			tv = &timeout;
-#endif
-		} else {
-#ifdef HAVE_POLL_H
-			timeout = INFTIM;
-#else
-			tv = NULL;
-#endif
-		}
-#ifdef HAVE_POLL_H
-		fdmaskp[0].fd = s;
-		fdmaskp[0].events = POLLIN;
-		cc = poll(fdmaskp, 1, timeout);
-#else
-		memset(fdmaskp, 0, fdmasks);
-		FD_SET(s, fdmaskp);
-		cc = select(s + 1, fdmaskp, NULL, NULL, tv);
-#endif
-		if (cc < 0) {
-			if (errno != EINTR) {
-#ifdef HAVE_POLL_H
-				warn("poll");
-#else
-				warn("select");
-#endif
-				sleep(1);
-			}
-			continue;
-		} else if (cc == 0)
-			continue;
-
-		m.msg_name = (caddr_t)&from;
-		m.msg_namelen = sizeof(from);
-		memset(&iov, 0, sizeof(iov));
-		iov[0].iov_base = (caddr_t)packet;
-		iov[0].iov_len = packlen;
-		m.msg_iov = iov;
-		m.msg_iovlen = 1;
-		memset(cm, 0, CONTROLLEN);
-		m.msg_control = (void *)cm;
-		m.msg_controllen = CONTROLLEN;
-
-		cc = recvmsg(s, &m, 0);
-		if (cc < 0) {
-			if (errno != EINTR) {
-				warn("recvmsg");
-				sleep(1);
-			}
-			continue;
-		} else if (cc == 0) {
-			int mtu;
-
-			/*
-			 * receive control messages only. Process the
-			 * exceptions (currently the only possibility is
-			 * a path MTU notification.)
-			 */
-			if ((mtu = get_pathmtu(&m)) > 0) {
-				if ((options & F_VERBOSE) != 0) {
-					printf("new path MTU (%d) is "
-					    "notified\n", mtu);
+				/*
+				 * receive control messages only. Process the
+				 * exceptions (currently the only possibility is
+				 * a path MTU notification.)
+				 */
+				if ((mtu = get_pathmtu(&m)) > 0) {
+					if ((options & F_VERBOSE) != 0) {
+						printf("new path MTU (%d) is "
+						    "notified\n", mtu);
+					}
 				}
+				continue;
+			} else {
+				/*
+				 * an ICMPv6 message (probably an echoreply)
+				 * arrived.
+				 */
+				pr_pack(packet, cc, &m);
 			}
-			continue;
-		} else {
+			if (((options & F_ONCE) != 0 && nreceived > 0) ||
+			    (npackets > 0 && nreceived >= npackets))
+				break;
+		}
+		if (n == 0 || (options & F_FLOOD)) {
+			if (npackets == 0 || ntransmitted < npackets)
+				pinger();
+			else {
+				if (almost_done)
+					break;
+				almost_done = 1;
 			/*
-			 * an ICMPv6 message (probably an echoreply) arrived.
+			 * 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.
 			 */
-			pr_pack(packet, cc, &m);
-		}
-		if (((options & F_ONCE) != 0 && nreceived > 0) ||
-		    (npackets > 0 && nreceived >= npackets))
-			break;
-		if (ntransmitted - nreceived - 1 > nmissedmax) {
-			nmissedmax = ntransmitted - nreceived - 1;
-			if (options & F_MISSED)
-				(void)write(STDOUT_FILENO, &BBELL, 1);
+#define	MAXWAIT		10
+				intvl.tv_usec = 0;
+				if (nreceived) {
+					intvl.tv_sec = 2 * tmax / 1000;
+					if (intvl.tv_sec == 0)
+						intvl.tv_sec = 1;
+				} else
+					intvl.tv_sec = MAXWAIT;
+			}
+			gettimeofday(&last, NULL);
+			if (ntransmitted - nreceived - 1 > nmissedmax) {
+				nmissedmax = ntransmitted - nreceived - 1;
+				if (options & F_MISSED)
+					(void)write(STDOUT_FILENO, &BBELL, 1);
+			}
 		}
 	}
+	sigemptyset(&si_sa.sa_mask);
+	si_sa.sa_flags = 0;
+	si_sa.sa_handler = SIG_IGN;
+	sigaction(SIGINT, &si_sa, 0);
 	summary();
 
 	if (res != NULL)
@@ -1203,11 +1189,6 @@ main(int argc, char *argv[])
         if(packet != NULL)
                 free(packet);
 
-#ifndef HAVE_POLL_H
-        if(fdmaskp != NULL)
-                free(fdmaskp);
-#endif
-
 	exit(nreceived == 0 ? 2 : 0);
 }
 
@@ -1216,9 +1197,6 @@ onsignal(int sig)
 {
 
 	switch (sig) {
-	case SIGALRM:
-		seenalrm++;
-		break;
 	case SIGINT:
 		seenint++;
 		break;
@@ -1231,38 +1209,6 @@ onsignal(int sig)
 }
 
 /*
- * retransmit --
- *	This routine transmits another ping6.
- */
-void
-retransmit(void)
-{
-	struct itimerval itimer;
-
-	if (pinger() == 0)
-		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, onsignal);
-	(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,
@@ -2241,24 +2187,12 @@ tvsub(struct timeval *out, struct timeva
 void
 onint(int notused __unused)
 {
-	summary();
-
-	if (res != NULL)
-		freeaddrinfo(res);
-
-        if(packet != NULL)
-                free(packet);
-
-#ifndef HAVE_POLL_H
-        if(fdmaskp != NULL)
-                free(fdmaskp);
-#endif
-
-	(void)signal(SIGINT, SIG_DFL);
-	(void)kill(getpid(), SIGINT);
-
-	/* NOTREACHED */
-	exit(1);
+	/*
+	 * When doing reverse DNS lookups, the seenint flag might not
+	 * be noticed for a while.  Just exit if we get a second SIGINT.
+	 */
+	if ((options & F_HOSTNAME) && seenint != 0)
+		_exit(nreceived ? 0 : 2);
 }
 
 /*



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201409201954.s8KJsJnE086075>