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. >
--
