Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sbin/ping6 Fix rump.ping6 -c N (N > 1) doesn't work



details:   https://anonhg.NetBSD.org/src/rev/987a578a9143
branches:  trunk
changeset: 341395:987a578a9143
user:      ozaki-r <ozaki-r%NetBSD.org@localhost>
date:      Wed Nov 04 08:07:54 2015 +0000

description:
Fix rump.ping6 -c N (N > 1) doesn't work

2nd packet and subsequent packets are sent based on SIGALRM and
it depends on poll(2) returns with EINTR by the signal. However,
currently poll is rump-ified while signals aren't so the signal
doesn't wake up poll and ping6 doesn't work expectedly.

Rump-ifying signals is unsure (nobody does it for now) and the
combination use of signals and poll makes the logic a bit complex.
So let's fix the defect by stopping using signals for packet
transmissions. The new logic is derived from ping(8).

Bonus: ping6 -i 0.01 works as we expect now while the original
didn't work enough fast.

diffstat:

 sbin/ping6/ping6.c |  201 ++++++++++++++++++++++++++++------------------------
 1 files changed, 109 insertions(+), 92 deletions(-)

diffs (truncated from 376 to 300 lines):

diff -r ba7ed3a9c45f -r 987a578a9143 sbin/ping6/ping6.c
--- a/sbin/ping6/ping6.c        Wed Nov 04 07:59:25 2015 +0000
+++ b/sbin/ping6/ping6.c        Wed Nov 04 08:07:54 2015 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ping6.c,v 1.90 2015/11/04 07:59:25 ozaki-r Exp $       */
+/*     $NetBSD: ping6.c,v 1.91 2015/11/04 08:07:54 ozaki-r Exp $       */
 /*     $KAME: ping6.c,v 1.164 2002/11/16 14:05:37 itojun Exp $ */
 
 /*
@@ -77,7 +77,7 @@
 #else
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: ping6.c,v 1.90 2015/11/04 07:59:25 ozaki-r Exp $");
+__RCSID("$NetBSD: ping6.c,v 1.91 2015/11/04 08:07:54 ozaki-r Exp $");
 #endif
 #endif
 
@@ -229,7 +229,10 @@
 static long nreceived;                 /* # of packets we got back */
 static long nrepeats;                  /* number of duplicates */
 static long ntransmitted;              /* sequence # for outbound packets = #sent */
-static struct timeval interval = {1, 0}; /* interval between packets */
+static struct timespec interval = {1, 0}; /* interval between packets */
+
+static struct timespec now, last_tx, next_tx, first_tx;
+static int lastrcvd = 1;                       /* last ping sent has been received */
 
 /* timing */
 static int timing;                     /* flag to do timing */
@@ -248,21 +251,20 @@
 static struct iovec smsgiov;
 static char *scmsg = 0;
 
-static volatile sig_atomic_t seenalrm;
 static volatile sig_atomic_t seenint;
 #ifdef SIGINFO
 static volatile sig_atomic_t seeninfo;
 #endif
 
+__dead static void     doit(u_char *, u_int);
 static void     fill(char *, char *);
 static int      get_hoplim(struct msghdr *);
 static int      get_pathmtu(struct msghdr *);
 static struct in6_pktinfo *get_rcvpktinfo(struct msghdr *);
 static void     onsignal(int);
-static void     retransmit(void);
 __dead static void      onsigexit(int);
 static size_t   pingerlen(void);
-static int      pinger(void);
+static void     pinger(void);
 static const char *pr_addr(struct sockaddr *, int);
 static void     pr_icmph(struct icmp6_hdr *, u_char *);
 static void     pr_iph(struct ip6_hdr *);
@@ -283,17 +285,13 @@
 static int      setpolicy(int, char *);
 static char    *nigroup(char *);
 static double  timespec_to_sec(const struct timespec *tp);
+static double  diffsec(struct timespec *, struct timespec *);
 __dead static void      usage(void);
 
 int
 main(int argc, char *argv[])
 {
-       struct itimerval itimer;
-       struct sockaddr_in6 from;
-       int timeout;
        struct addrinfo hints;
-       struct pollfd fdmaskp[1];
-       int cc;
        u_int i, packlen;
        int ch, hold, preload, optval, ret_ga;
        u_char *datap, *packet;
@@ -316,8 +314,6 @@
 #ifdef IPV6_USE_MIN_MTU
        int mflag = 0;
 #endif
-       struct timespec now;
-       double exitat = 0.0;
 
        /* just to be sure */
        memset(&smsghdr, 0, sizeof(smsghdr));
@@ -415,6 +411,8 @@
                        }
                        options |= F_FLOOD;
                        setbuf(stdout, NULL);
+                       interval.tv_sec = 0;
+                       interval.tv_nsec = 10 * 1000 * 1000; /* 10 ms */
                        break;
                case 'g':
                        gateway = optarg;
@@ -446,14 +444,15 @@
                                    strerror(EPERM));
                        }
                        interval.tv_sec = (long)intval;
-                       interval.tv_usec =
-                           (long)((intval - interval.tv_sec) * 1000000);
+                       interval.tv_nsec =
+                           (long)((intval - interval.tv_sec) * 1000000000);
                        if (interval.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 < 10000) {
+                       if (interval.tv_sec == 0 &&
+                           interval.tv_nsec < 10000000) {
                                warnx("too small interval, raised to 0.01");
-                               interval.tv_usec = 10000;
+                               interval.tv_nsec = 10000000;
                        }
                        options |= F_INTERVAL;
                        break;
@@ -1026,50 +1025,51 @@
        printf("%s\n", pr_addr((struct sockaddr *)&dst, sizeof(dst)));
 
        while (preload--)               /* Fire off them quickies. */
-               (void)pinger();
+               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();
-       }
-
-       if (deadline > 0) {
-               clock_gettime(CLOCK_MONOTONIC, &now);
-               exitat = timespec_to_sec(&now) + deadline;
-       }
-
-       seenalrm = seenint = 0;
+       seenint = 0;
 #ifdef SIGINFO
        seeninfo = 0;
 #endif
 
+       doit(packet, packlen);
+       /*NOTREACHED*/
+       return 0;
+}
+
+static void
+doit(u_char *packet, u_int packlen)
+{
+       int cc;
+       struct pollfd fdmaskp[1];
+       struct sockaddr_in6 from;
+       double sec, last, d_last;
+       long orig_npackets = npackets;
+
+       if (npackets == 0)
+               npackets = LONG_MAX;
+
+       clock_gettime(CLOCK_MONOTONIC, &now);
+       if (deadline > 0) {
+               last = timespec_to_sec(&now) + deadline;
+               d_last = 0;
+       } else {
+               last = 0;
+               d_last = 365*24*60*60;
+       }
+
        for (;;) {
                struct msghdr m;
                u_char buf[1024];
                struct iovec iov[2];
 
-               /* check deadline */
-               if (exitat > 0) {
-                       clock_gettime(CLOCK_MONOTONIC, &now);
-                       if (exitat <= timespec_to_sec(&now))
-                               break;
-               }
+               clock_gettime(CLOCK_MONOTONIC, &now);
 
-               /* signal handling */
-               if (seenalrm) {
-                       retransmit();
-                       seenalrm = 0;
-                       continue;
-               }
                if (seenint) {
                        onsigexit(SIGINT);
                        seenint = 0;
@@ -1082,17 +1082,37 @@
                        continue;
                }
 #endif
-               if (options & F_FLOOD) {
-                       (void)pinger();
-                       timeout = 10;
-               } else if (deadline > 0) {
-                       timeout = (int)floor(deadline * 1000);
+               if (last != 0)
+                       d_last = last - timespec_to_sec(&now);
+
+               if (ntransmitted < npackets && d_last > 0) {
+                       /* send if within 100 usec or late for next packet */
+                       sec = diffsec(&next_tx, &now);
+                       if ((sec <= 0.0001 && (options & F_FLOOD) == 0) ||
+                           (lastrcvd && (options & F_FLOOD))) {
+                               pinger();
+                               sec = diffsec(&next_tx, &now);
+                       }
+                       if (sec < 0.0)
+                               sec = 0.0;
+                       if (d_last < sec)
+                               sec = d_last;
                } else {
-                       timeout = INFTIM;
+                       /* For the last response, wait twice as long as the
+                        * worst case seen, or 10 times as long as the
+                        * maximum interpacket interval, whichever is longer.
+                        */
+                       sec = MAX(2 * tmax, 10 * interval.tv_sec) -
+                           diffsec(&now, &last_tx);
+                       if (d_last < sec)
+                               sec = d_last;
+                       if (sec <= 0)
+                               break;
                }
+
                fdmaskp[0].fd = s;
                fdmaskp[0].events = POLLIN;
-               cc = prog_poll(fdmaskp, 1, timeout);
+               cc = prog_poll(fdmaskp, 1, (int)(sec * 1000));
                if (cc < 0) {
                        if (errno != EINTR) {
                                warn("poll");
@@ -1145,9 +1165,11 @@
                if (nreceived != 0 && (options & F_ONCE))
                        break;
        }
+
        summary();
-       if (npackets)
-               exit(nreceived != npackets);
+
+       if (orig_npackets)
+               exit(nreceived != orig_npackets);
        else
                exit(nreceived == 0);
 }
@@ -1157,9 +1179,6 @@
 {
 
        switch (sig) {
-       case SIGALRM:
-               seenalrm++;
-               break;
        case SIGINT:
                seenint++;
                break;
@@ -1172,38 +1191,6 @@
 }
 
 /*
- * retransmit --
- *     This routine transmits another ping6.
- */
-static 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, onsigexit);
-       (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,
@@ -1230,7 +1217,7 @@



Home | Main Index | Thread Index | Old Index