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);
 }
 
 /*
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to