This shoves a round peg into a square hole with considerable force...
I was only concerned with moving the functionality over from ping6,
further cleanup will happen on top of this.

OK?

diff --git ping.c ping.c
index 4944f77..a3a6fe3 100644
--- ping.c
+++ ping.c
@@ -147,8 +147,7 @@ unsigned long nreceived;    /* # of packets we got back */
 unsigned long nrepeats;                /* number of duplicates */
 unsigned long ntransmitted;    /* sequence # for outbound packets = #sent */
 unsigned long nmissedmax = 1;  /* max value of ntransmitted - nreceived - 1 */
-double interval = 1;           /* interval between packets */
-struct itimerval interstr;     /* interval structure for use with setitimer */
+struct timeval interval = {1, 0}; /* interval between packets */
 
 /* timing */
 int timing;                    /* flag to do timing */
@@ -163,17 +162,21 @@ int bufspace = IP_MAXPACKET;
 struct tv64 tv64_offset;
 SIPHASH_KEY mac_key;
 
+volatile sig_atomic_t seenalrm;
+volatile sig_atomic_t seenint;
+volatile sig_atomic_t seeninfo;
+
 void fill(char *, char *);
-void catcher(int signo);
-void prtsig(int signo);
-__dead void finish(int signo);
-void summary(int, int);
+void summary(int);
 int in_cksum(u_short *, int);
-void pinger(void);
+void onsignal(int);
+void retransmit(void);
+void onint(int);
+int pinger(void);
 char *pr_addr(in_addr_t);
 int check_icmph(struct ip *);
 void pr_icmph(struct icmp *);
-void pr_pack(char *, int, struct sockaddr_in *);
+void pr_pack(char *, int, struct msghdr *);
 void pr_retip(struct ip *);
 void pr_iph(struct ip *);
 #ifndef SMALL
@@ -186,15 +189,17 @@ main(int argc, char *argv[])
 {
        struct hostent *hp;
        struct addrinfo hints, *res;
-       struct sockaddr_in  from4;
+       struct itimerval itimer;
+       struct sockaddr_in  from, from4;
        struct sockaddr_in *to;
        int ch, i, optval = 1, packlen, preload, maxsize, df = 0, tos = 0;
        int error;
        u_char *datap, *packet, ttl = MAXTTL, loop = 1;
-       char *target, hnamebuf[HOST_NAME_MAX+1], *source = NULL;
+       char *e, *target, hnamebuf[HOST_NAME_MAX+1], *source = NULL;
        char rspace[3 + 4 * NROUTES + 1];       /* record route space */
        socklen_t maxsizelen;
        const char *errstr;
+       double intval;
        uid_t uid;
        u_int rtableid = 0;
 
@@ -242,19 +247,23 @@ main(int argc, char *argv[])
                        source = optarg;
                        break;
                case 'i':               /* wait between sending packets */
-                       interval = strtod(optarg, NULL);
-
-                       if (interval <= 0 || interval >= INT_MAX)
-                               errx(1, "bad timing interval: %s", optarg);
-
-                       if (interval < 1)
-                               if (getuid())
-                                       errx(1, "%s: only root may use interval 
< 1s",
-                                           strerror(EPERM));
-
-                       if (interval < 0.01)
-                               interval = 0.01;
-
+                       intval = strtod(optarg, &e);
+                       if (*optarg == '\0' || *e != '\0')
+                               errx(1, "illegal timing interval %s", optarg);
+                       if (intval < 1 && getuid()) {
+                               errx(1, "%s: only root may use interval < 1s",
+                                   strerror(EPERM));
+                       }
+                       interval.tv_sec = (time_t)intval;
+                       interval.tv_usec =
+                           (long)((intval - interval.tv_sec) * 1000000);
+                       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) {
+                               warnx("too small interval, raised to 0.01");
+                               interval.tv_usec = 10000;
+                       }
                        options |= F_INTERVAL;
                        break;
                case 'L':
@@ -387,12 +396,6 @@ main(int argc, char *argv[])
        arc4random_buf(&tv64_offset, sizeof(tv64_offset));
        arc4random_buf(&mac_key, sizeof(mac_key));
 
-       memset(&interstr, 0, sizeof(interstr));
-
-       interstr.it_value.tv_sec = interval;
-       interstr.it_value.tv_usec =
-               (long) ((interval - interstr.it_value.tv_sec) * 1000000);
-
        if (options & F_FLOOD && options & F_INTERVAL)
                errx(1, "-f and -i options are incompatible");
 
@@ -508,26 +511,54 @@ main(int argc, char *argv[])
                        err(1, "pledge");
        }
 
-       (void)signal(SIGINT, finish);
-       (void)signal(SIGALRM, catcher);
-       (void)signal(SIGINFO, prtsig);
-
        while (preload--)               /* fire off them quickies */
                pinger();
 
-       if ((options & F_FLOOD) == 0)
-               catcher(0);             /* start things going */
+       (void)signal(SIGINT, onsignal);
+       (void)signal(SIGINFO, onsignal);
+
+       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();
+       }
+
+       seenalrm = seenint = 0;
+       seeninfo = 0;
 
        for (;;) {
-               struct sockaddr_in      from;
-               sigset_t                omask, nmask;
-               socklen_t               fromlen;
-               struct pollfd           pfd;
-               ssize_t                 cc;
-               int                     timeout;
+               struct msghdr   m;
+               union {
+                       struct cmsghdr hdr;
+                       u_char buf[CMSG_SPACE(1024)];
+               }               cmsgbuf;
+               struct iovec    iov[1];
+               struct pollfd   pfd;
+               ssize_t         cc;
+               int             timeout;
+
+               /* signal handling */
+               if (seenalrm) {
+                       retransmit();
+                       seenalrm = 0;
+                       continue;
+               }
+               if (seenint) {
+                       onint(SIGINT);
+                       seenint = 0;
+                       continue;
+               }
+               if (seeninfo) {
+                       summary(0);
+                       seeninfo = 0;
+                       continue;
+               }
 
                if (options & F_FLOOD) {
-                       pinger();
+                       (void)pinger();
                        timeout = 10;
                } else
                        timeout = INFTIM;
@@ -538,76 +569,85 @@ main(int argc, char *argv[])
                if (poll(&pfd, 1, timeout) <= 0)
                        continue;
 
-               fromlen = sizeof(from);
-               if ((cc = recvfrom(s, packet, packlen, 0,
-                   (struct sockaddr *)&from, &fromlen)) < 0) {
-                       if (errno == EINTR)
-                               continue;
-                       perror("ping: recvfrom");
+               m.msg_name = &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;
+               m.msg_control = (caddr_t)&cmsgbuf.buf;
+               m.msg_controllen = sizeof(cmsgbuf.buf);
+
+               cc = recvmsg(s, &m, 0);
+               if (cc < 0) {
+                       if (errno != EINTR) {
+                               warn("recvmsg");
+                               sleep(1);
+                       }
                        continue;
-               }
-               sigemptyset(&nmask);
-               sigaddset(&nmask, SIGALRM);
-               sigprocmask(SIG_BLOCK, &nmask, &omask);
-               pr_pack((char *)packet, cc, &from);
-               sigprocmask(SIG_SETMASK, &omask, NULL);
+               } else
+                       pr_pack(packet, cc, &m);
+
                if (npackets && nreceived >= npackets)
                        break;
+               if (ntransmitted - nreceived - 1 > nmissedmax) {
+                       nmissedmax = ntransmitted - nreceived - 1;
+                       if (!(options & F_FLOOD) && (options & F_AUD_MISS))
+                               (void)fputc('\a', stderr);
+               }
+
        }
-       finish(0);
-       /* NOTREACHED */
+       summary(0);
+       exit(nreceived == 0);
 }
 
-/*
- * 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.
- */
-/* ARGSUSED */
+
 void
-catcher(int signo)
+onsignal(int sig)
 {
-       int save_errno = errno;
-       unsigned int waittime;
-
-       pinger();
-       (void)signal(SIGALRM, catcher);
-       if (!npackets || ntransmitted < npackets)
-               setitimer(ITIMER_REAL, &interstr, (struct itimerval *)0);
-       else {
-               if (nreceived) {
-                       waittime = 2 * tmax / 1000000;
-                       if (!waittime)
-                               waittime = 1;
-               } else
-                       waittime = maxwait;
-               (void)signal(SIGALRM, finish);
-               (void)alarm(waittime);
-       }
-       if (ntransmitted - nreceived - 1 > nmissedmax) {
-               nmissedmax = ntransmitted - nreceived - 1;
-               if (!(options & F_FLOOD) && (options & F_AUD_MISS))
-                       write(STDERR_FILENO, "\a", 1);
+       switch (sig) {
+       case SIGALRM:
+               seenalrm++;
+               break;
+       case SIGINT:
+               seenint++;
+               break;
+       case SIGINFO:
+               seeninfo++;
+               break;
        }
-       errno = save_errno;
 }
 
 /*
- * Print statistics when SIGINFO is received.
+ * retransmit --
+ *     This routine transmits another ping.
  */
-/* ARGSUSED */
 void
-prtsig(int signo)
+retransmit(void)
 {
-       int save_errno = errno;
+       struct itimerval itimer;
 
-       summary(0, 1);
-       errno = save_errno;
+       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
+        * maxwait seconds if we haven't.
+        */
+       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);
 }
 
 /*
@@ -618,13 +658,16 @@ prtsig(int signo)
  * of the data portion are used to hold a UNIX "timeval" struct in VAX
  * byte-order, to compute the round-trip time.
  */
-void
+int
 pinger(void)
 {
        struct icmp *icp;
        int cc, i;
        u_char *packet = outpack;
 
+       if (npackets && ntransmitted >= npackets)
+               return(-1);     /* no more transmission */
+
        icp = (struct icmp *)outpack;
        icp->icmp_type = ICMP_ECHO;
        icp->icmp_code = 0;
@@ -685,6 +728,7 @@ pinger(void)
                (void)write(STDOUT_FILENO, &DOT, 1);
 
        ntransmitted++;
+       return (0);
 }
 
 /*
@@ -695,8 +739,10 @@ pinger(void)
  * program to be run without having intermingled output (or statistics!).
  */
 void
-pr_pack(char *buf, int cc, struct sockaddr_in *from)
+pr_pack(char *buf, int cc, struct msghdr *mhdr)
 {
+       struct sockaddr_in *from;
+       socklen_t fromlen;
        struct icmp *icp;
        in_addr_t l;
        u_int i, j;
@@ -713,6 +759,16 @@ pr_pack(char *buf, int cc, struct sockaddr_in *from)
        if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
                err(1, "clock_gettime(CLOCK_MONOTONIC)");
 
+       if (!mhdr || !mhdr->msg_name ||
+           mhdr->msg_namelen != sizeof(struct sockaddr_in) ||
+           ((struct sockaddr *)mhdr->msg_name)->sa_family != AF_INET) {
+               if (options & F_VERBOSE)
+                       warnx("invalid peername");
+               return;
+       }
+       from = (struct sockaddr_in *)mhdr->msg_name;
+       fromlen = mhdr->msg_namelen;
+
        /* Check the IP header */
        ip = (struct ip *)buf;
        hlen = ip->ip_hl << 2;
@@ -967,8 +1023,23 @@ in_cksum(u_short *addr, int len)
        return(answer);
 }
 
+/*
+ * onint --
+ *     SIGINT handler.
+ */
+void
+onint(int signo)
+{
+       summary(signo);
+
+       if (signo)
+               _exit(nreceived ? 0 : 1);
+       else
+               exit(nreceived ? 0 : 1);
+}
+
 void
-summary(int header, int insig)
+summary(int insig)
 {
        char buf[8192], buft[8192];
 
@@ -980,11 +1051,10 @@ summary(int header, int insig)
        } else
                strlcat(buf, "\r", sizeof buf);
 
-       if (header) {
-               snprintf(buft, sizeof buft, "--- %s ping statistics ---\n",
-                   hostname);
-               strlcat(buf, buft, sizeof buf);
-       }
+
+       snprintf(buft, sizeof buft, "--- %s ping statistics ---\n",
+           hostname);
+       strlcat(buf, buft, sizeof buf);
 
        snprintf(buft, sizeof buft, "%ld packets transmitted, ", ntransmitted);
        strlcat(buf, buft, sizeof buf);
@@ -1020,22 +1090,6 @@ summary(int header, int insig)
 }
 
 /*
- * finish --
- *     Print out statistics, and give up.
- */
-__dead void
-finish(int signo)
-{
-       (void)signal(SIGINT, SIG_IGN);
-
-       summary(1, signo);
-       if (signo)
-               _exit(nreceived ? 0 : 1);
-       else
-               exit(nreceived ? 0 : 1);
-}
-
-/*
  * pr_icmph --
  *     Print a descriptive string about an ICMP header.
  */

-- 
I'm not entirely sure you are real.

Reply via email to