ok

Florian Obser([email protected]) on 2015.11.29 15:57:34 +0000:
> 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