Ditch the sysvinit stuff
[profile/ivi/iputils.git] / ping_common.c
1 #include "ping_common.h"
2 #include <ctype.h>
3 #include <sched.h>
4
5 int options;
6
7 int mark;
8 int sndbuf;
9 int ttl;
10 int rtt;
11 int rtt_addend;
12 __u16 acked;
13
14 int mx_dup_ck = MAX_DUP_CHK;
15 char rcvd_tbl[MAX_DUP_CHK / 8];
16
17
18 /* counters */
19 long npackets;                  /* max packets to transmit */
20 long nreceived;                 /* # of packets we got back */
21 long nrepeats;                  /* number of duplicates */
22 long ntransmitted;              /* sequence # for outbound packets = #sent */
23 long nchecksum;                 /* replies with bad checksum */
24 long nerrors;                   /* icmp errors */
25 int interval = 1000;            /* interval between packets (msec) */
26 int preload;
27 int deadline = 0;               /* time to die */
28 int lingertime = MAXWAIT*1000;
29 struct timeval start_time, cur_time;
30 volatile int exiting;
31 volatile int status_snapshot;
32 int confirm = 0;
33
34 /* Stupid workarounds for bugs/missing functionality in older linuces.
35  * confirm_flag fixes refusing service of kernels without MSG_CONFIRM.
36  * i.e. for linux-2.2 */
37 int confirm_flag = MSG_CONFIRM;
38 /* And this is workaround for bug in IP_RECVERR on raw sockets which is present
39  * in linux-2.2.[0-19], linux-2.4.[0-7] */
40 int working_recverr;
41
42 /* timing */
43 int timing;                     /* flag to do timing */
44 long tmin = LONG_MAX;           /* minimum round trip time */
45 long tmax;                      /* maximum round trip time */
46 /* Message for rpm maintainers: have _shame_. If you want
47  * to fix something send the patch to me for sanity checking.
48  * "sparcfix" patch is a complete non-sense, apparenly the person
49  * prepared it was stoned.
50  */
51 long long tsum;                 /* sum of all times, for doing average */
52 long long tsum2;
53 int  pipesize = -1;
54
55 int datalen = DEFDATALEN;
56
57 char *hostname;
58 int uid;
59 int ident;                      /* process id to identify our packets */
60
61 static int screen_width = INT_MAX;
62
63 /* Fills all the outpack, excluding ICMP header, but _including_
64  * timestamp area with supplied pattern.
65  */
66 static void fill(char *patp)
67 {
68         int ii, jj, kk;
69         int pat[16];
70         char *cp;
71         u_char *bp = outpack+8;
72
73         for (cp = patp; *cp; cp++) {
74                 if (!isxdigit(*cp)) {
75                         fprintf(stderr,
76                                 "ping: patterns must be specified as hex digits.\n");
77                         exit(2);
78                 }
79         }
80         ii = sscanf(patp,
81             "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
82             &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6],
83             &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12],
84             &pat[13], &pat[14], &pat[15]);
85
86         if (ii > 0) {
87                 for (kk = 0; kk <= maxpacket - (8 + ii); kk += ii)
88                         for (jj = 0; jj < ii; ++jj)
89                                 bp[jj + kk] = pat[jj];
90         }
91         if (!(options & F_QUIET)) {
92                 printf("PATTERN: 0x");
93                 for (jj = 0; jj < ii; ++jj)
94                         printf("%02x", bp[jj] & 0xFF);
95                 printf("\n");
96         }
97 }
98
99 void common_options(int ch)
100 {
101         switch(ch) {
102         case 'a':
103                 options |= F_AUDIBLE;
104                 break;
105         case 'A':
106                 options |= F_ADAPTIVE;
107                 break;
108         case 'c':
109                 npackets = atoi(optarg);
110                 if (npackets <= 0) {
111                         fprintf(stderr, "ping: bad number of packets to transmit.\n");
112                         exit(2);
113                 }
114                 break;
115         case 'd':
116                 options |= F_SO_DEBUG;
117                 break;
118         case 'D':
119                 options |= F_PTIMEOFDAY;
120                 break;
121         case 'i':               /* wait between sending packets */
122         {
123                 if (strchr(optarg, '.')) {
124                         float t;
125                         if (sscanf(optarg, "%f", &t) != 1) {
126                                 fprintf(stderr, "ping: bad timing interval.\n");
127                                 exit(2);
128                         }
129                         interval = (int)(t*1000);
130                 } else if (sscanf(optarg, "%d", &interval) == 1) {
131                         interval *= 1000;
132                 } else {
133                         fprintf(stderr, "ping: bad timing interval.\n");
134                         exit(2);
135                 }
136
137                 if (interval < 0) {
138                         fprintf(stderr, "ping: bad timing interval.\n");
139                         exit(2);
140                 }
141                 options |= F_INTERVAL;
142                 break;
143         }
144         case 'm':
145         {
146                 char *endp;
147                 mark = (int)strtoul(optarg, &endp, 10);
148                 if (mark < 0 || *endp != '\0') {
149                         fprintf(stderr, "mark cannot be negative");
150                         exit(2);
151                 }
152                 options |= F_MARK;
153                 break;
154         }
155         case 'w':
156                 deadline = atoi(optarg);
157                 if (deadline < 0) {
158                         fprintf(stderr, "ping: bad wait time.\n");
159                         exit(2);
160                 }
161                 break;
162         case 'l':
163                 preload = atoi(optarg);
164                 if (preload <= 0) {
165                         fprintf(stderr, "ping: bad preload value, should be 1..%d\n", mx_dup_ck);
166                         exit(2);
167                 }
168                 if (preload > mx_dup_ck)
169                         preload = mx_dup_ck;
170                 if (uid && preload > 3) {
171                         fprintf(stderr, "ping: cannot set preload to value > 3\n");
172                         exit(2);
173                 }
174                 break;
175         case 'S':
176                 sndbuf = atoi(optarg);
177                 if (sndbuf <= 0) {
178                         fprintf(stderr, "ping: bad sndbuf value.\n");
179                         exit(2);
180                 }
181                 break;
182         case 'f':
183                 options |= F_FLOOD;
184                 setbuf(stdout, (char *)NULL);
185                 /* fallthrough to numeric - avoid gethostbyaddr during flood */
186         case 'n':
187                 options |= F_NUMERIC;
188                 break;
189         case 'p':               /* fill buffer with user pattern */
190                 options |= F_PINGFILLED;
191                 fill(optarg);
192                 break;
193         case 'q':
194                 options |= F_QUIET;
195                 break;
196         case 'r':
197                 options |= F_SO_DONTROUTE;
198                 break;
199         case 's':               /* size of packet to send */
200                 datalen = atoi(optarg);
201                 if (datalen < 0) {
202                         fprintf(stderr, "ping: illegal negative packet size %d.\n", datalen);
203                         exit(2);
204                 }
205                 if (datalen > maxpacket - 8) {
206                         fprintf(stderr, "ping: packet size too large: %d\n",
207                                 datalen);
208                         exit(2);
209                 }
210                 break;
211         case 'v':
212                 options |= F_VERBOSE;
213                 break;
214         case 'L':
215                 options |= F_NOLOOP;
216                 break;
217         case 't':
218                 options |= F_TTL;
219                 ttl = atoi(optarg);
220                 if (ttl < 0 || ttl > 255) {
221                         fprintf(stderr, "ping: ttl %u out of range\n", ttl);
222                         exit(2);
223                 }
224                 break;
225         case 'U':
226                 options |= F_LATENCY;
227                 break;
228         case 'B':
229                 options |= F_STRICTSOURCE;
230                 break;
231         case 'W':
232                 lingertime = atoi(optarg);
233                 if (lingertime < 0 || lingertime > INT_MAX/1000000) {
234                         fprintf(stderr, "ping: bad linger time.\n");
235                         exit(2);
236                 }
237                 lingertime *= 1000;
238                 break;
239         case 'V':
240                 printf("ping utility, iputils-ss%s\n", SNAPSHOT);
241                 exit(0);
242         default:
243                 abort();
244         }
245 }
246
247
248 static void sigexit(int signo)
249 {
250         exiting = 1;
251 }
252
253 static void sigstatus(int signo)
254 {
255         status_snapshot = 1;
256 }
257
258
259 int __schedule_exit(int next)
260 {
261         static unsigned long waittime;
262         struct itimerval it;
263
264         if (waittime)
265                 return next;
266
267         if (nreceived) {
268                 waittime = 2 * tmax;
269                 if (waittime < 1000*interval)
270                         waittime = 1000*interval;
271         } else
272                 waittime = lingertime*1000;
273
274         if (next < 0 || next < waittime/1000)
275                 next = waittime/1000;
276
277         it.it_interval.tv_sec = 0;
278         it.it_interval.tv_usec = 0;
279         it.it_value.tv_sec = waittime/1000000;
280         it.it_value.tv_usec = waittime%1000000;
281         setitimer(ITIMER_REAL, &it, NULL);
282         return next;
283 }
284
285 static inline void update_interval(void)
286 {
287         int est = rtt ? rtt/8 : interval*1000;
288
289         interval = (est+rtt_addend+500)/1000;
290         if (uid && interval < MINUSERINTERVAL)
291                 interval = MINUSERINTERVAL;
292 }
293
294 /*
295  * Print timestamp
296  */
297 void print_timestamp(void)
298 {
299         if (options & F_PTIMEOFDAY) {
300                 struct timeval tv;
301                 gettimeofday(&tv, NULL);
302                 printf("[%lu.%06lu] ",
303                        (unsigned long)tv.tv_sec, (unsigned long)tv.tv_usec);
304         }
305 }
306
307 /*
308  * pinger --
309  *      Compose and transmit an ICMP ECHO REQUEST packet.  The IP packet
310  * will be added on by the kernel.  The ID field is our UNIX process ID,
311  * and the sequence number is an ascending integer.  The first 8 bytes
312  * of the data portion are used to hold a UNIX "timeval" struct in VAX
313  * byte-order, to compute the round-trip time.
314  */
315 int pinger(void)
316 {
317         static int oom_count;
318         static int tokens;
319         int i;
320
321         /* Have we already sent enough? If we have, return an arbitrary positive value. */
322         if (exiting || (npackets && ntransmitted >= npackets && !deadline))
323                 return 1000;
324
325         /* Check that packets < rate*time + preload */
326         if (cur_time.tv_sec == 0) {
327                 gettimeofday(&cur_time, NULL);
328                 tokens = interval*(preload-1);
329         } else {
330                 long ntokens;
331                 struct timeval tv;
332
333                 gettimeofday(&tv, NULL);
334                 ntokens = (tv.tv_sec - cur_time.tv_sec)*1000 +
335                         (tv.tv_usec-cur_time.tv_usec)/1000;
336                 if (!interval) {
337                         /* Case of unlimited flood is special;
338                          * if we see no reply, they are limited to 100pps */
339                         if (ntokens < MININTERVAL && in_flight() >= preload)
340                                 return MININTERVAL-ntokens;
341                 }
342                 ntokens += tokens;
343                 if (ntokens > interval*preload)
344                         ntokens = interval*preload;
345                 if (ntokens < interval)
346                         return interval - ntokens;
347
348                 cur_time = tv;
349                 tokens = ntokens - interval;
350         }
351
352 resend:
353         i = send_probe();
354
355         if (i == 0) {
356                 oom_count = 0;
357                 advance_ntransmitted();
358                 if (!(options & F_QUIET) && (options & F_FLOOD)) {
359                         /* Very silly, but without this output with
360                          * high preload or pipe size is very confusing. */
361                         if ((preload < screen_width && pipesize < screen_width) ||
362                             in_flight() < screen_width)
363                                 write(STDOUT_FILENO, ".", 1);
364                 }
365                 return interval - tokens;
366         }
367
368         /* And handle various errors... */
369         if (i > 0) {
370                 /* Apparently, it is some fatal bug. */
371                 abort();
372         } else if (errno == ENOBUFS || errno == ENOMEM) {
373                 int nores_interval;
374
375                 /* Device queue overflow or OOM. Packet is not sent. */
376                 tokens = 0;
377                 /* Slowdown. This works only in adaptive mode (option -A) */
378                 rtt_addend += (rtt < 8*50000 ? rtt/8 : 50000);
379                 if (options&F_ADAPTIVE)
380                         update_interval();
381                 nores_interval = SCHINT(interval/2);
382                 if (nores_interval > 500)
383                         nores_interval = 500;
384                 oom_count++;
385                 if (oom_count*nores_interval < lingertime)
386                         return nores_interval;
387                 i = 0;
388                 /* Fall to hard error. It is to avoid complete deadlock
389                  * on stuck output device even when dealine was not requested.
390                  * Expected timings are screwed up in any case, but we will
391                  * exit some day. :-) */
392         } else if (errno == EAGAIN) {
393                 /* Socket buffer is full. */
394                 tokens += interval;
395                 return MININTERVAL;
396         } else {
397                 if ((i=receive_error_msg()) > 0) {
398                         /* An ICMP error arrived. */
399                         tokens += interval;
400                         return MININTERVAL;
401                 }
402                 /* Compatibility with old linuces. */
403                 if (i == 0 && confirm_flag && errno == EINVAL) {
404                         confirm_flag = 0;
405                         errno = 0;
406                 }
407                 if (!errno)
408                         goto resend;
409         }
410
411         /* Hard local error. Pretend we sent packet. */
412         advance_ntransmitted();
413
414         if (i == 0 && !(options & F_QUIET)) {
415                 if (options & F_FLOOD)
416                         write(STDOUT_FILENO, "E", 1);
417                 else
418                         perror("ping: sendmsg");
419         }
420         tokens = 0;
421         return SCHINT(interval);
422 }
423
424 /* Set socket buffers, "alloc" is an estimate of memory taken by single packet. */
425
426 void sock_setbufs(int icmp_sock, int alloc)
427 {
428         int rcvbuf, hold;
429         socklen_t tmplen = sizeof(hold);
430
431         if (!sndbuf)
432                 sndbuf = alloc;
433         setsockopt(icmp_sock, SOL_SOCKET, SO_SNDBUF, (char *)&sndbuf, sizeof(sndbuf));
434
435         rcvbuf = hold = alloc * preload;
436         if (hold < 65536)
437                 hold = 65536;
438         setsockopt(icmp_sock, SOL_SOCKET, SO_RCVBUF, (char *)&hold, sizeof(hold));
439         if (getsockopt(icmp_sock, SOL_SOCKET, SO_RCVBUF, (char *)&hold, &tmplen) == 0) {
440                 if (hold < rcvbuf)
441                         fprintf(stderr, "WARNING: probably, rcvbuf is not enough to hold preload.\n");
442         }
443 }
444
445 /* Protocol independent setup and parameter checks. */
446
447 void setup(int icmp_sock)
448 {
449         int hold;
450         struct timeval tv;
451
452         if ((options & F_FLOOD) && !(options & F_INTERVAL))
453                 interval = 0;
454
455         if (uid && interval < MINUSERINTERVAL) {
456                 fprintf(stderr, "ping: cannot flood; minimal interval, allowed for user, is %dms\n", MINUSERINTERVAL);
457                 exit(2);
458         }
459
460         if (interval >= INT_MAX/preload) {
461                 fprintf(stderr, "ping: illegal preload and/or interval\n");
462                 exit(2);
463         }
464
465         hold = 1;
466         if (options & F_SO_DEBUG)
467                 setsockopt(icmp_sock, SOL_SOCKET, SO_DEBUG, (char *)&hold, sizeof(hold));
468         if (options & F_SO_DONTROUTE)
469                 setsockopt(icmp_sock, SOL_SOCKET, SO_DONTROUTE, (char *)&hold, sizeof(hold));
470
471 #ifdef SO_TIMESTAMP
472         if (!(options&F_LATENCY)) {
473                 int on = 1;
474                 if (setsockopt(icmp_sock, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on)))
475                         fprintf(stderr, "Warning: no SO_TIMESTAMP support, falling back to SIOCGSTAMP\n");
476         }
477 #endif
478         if (options & F_MARK) {
479                 if (setsockopt(icmp_sock, SOL_SOCKET, SO_MARK,
480                                 &mark, sizeof(mark)) == -1) {
481                         /* we probably dont wanna exit since old kernels
482                          * dont support mark ..
483                         */
484                         fprintf(stderr, "Warning: Failed to set mark %d\n", mark);
485                 }
486         }
487
488         /* Set some SNDTIMEO to prevent blocking forever
489          * on sends, when device is too slow or stalls. Just put limit
490          * of one second, or "interval", if it is less.
491          */
492         tv.tv_sec = 1;
493         tv.tv_usec = 0;
494         if (interval < 1000) {
495                 tv.tv_sec = 0;
496                 tv.tv_usec = 1000 * SCHINT(interval);
497         }
498         setsockopt(icmp_sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&tv, sizeof(tv));
499
500         /* Set RCVTIMEO to "interval". Note, it is just an optimization
501          * allowing to avoid redundant poll(). */
502         tv.tv_sec = SCHINT(interval)/1000;
503         tv.tv_usec = 1000*(SCHINT(interval)%1000);
504         if (setsockopt(icmp_sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(tv)))
505                 options |= F_FLOOD_POLL;
506
507         if (!(options & F_PINGFILLED)) {
508                 int i;
509                 u_char *p = outpack+8;
510
511                 /* Do not forget about case of small datalen,
512                  * fill timestamp area too!
513                  */
514                 for (i = 0; i < datalen; ++i)
515                         *p++ = i;
516         }
517
518         ident = htons(getpid() & 0xFFFF);
519
520         set_signal(SIGINT, sigexit);
521         set_signal(SIGALRM, sigexit);
522         set_signal(SIGQUIT, sigstatus);
523
524         gettimeofday(&start_time, NULL);
525
526         if (deadline) {
527                 struct itimerval it;
528
529                 it.it_interval.tv_sec = 0;
530                 it.it_interval.tv_usec = 0;
531                 it.it_value.tv_sec = deadline;
532                 it.it_value.tv_usec = 0;
533                 setitimer(ITIMER_REAL, &it, NULL);
534         }
535
536         if (isatty(STDOUT_FILENO)) {
537                 struct winsize w;
538
539                 if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1) {
540                         if (w.ws_col > 0)
541                                 screen_width = w.ws_col;
542                 }
543         }
544 }
545
546 void main_loop(int icmp_sock, __u8 *packet, int packlen)
547 {
548         char addrbuf[128];
549         char ans_data[4096];
550         struct iovec iov;
551         struct msghdr msg;
552         struct cmsghdr *c;
553         int cc;
554         int next;
555         int polling;
556
557         iov.iov_base = (char *)packet;
558
559         for (;;) {
560                 /* Check exit conditions. */
561                 if (exiting)
562                         break;
563                 if (npackets && nreceived + nerrors >= npackets)
564                         break;
565                 if (deadline && nerrors)
566                         break;
567                 /* Check for and do special actions. */
568                 if (status_snapshot)
569                         status();
570
571                 /* Send probes scheduled to this time. */
572                 do {
573                         next = pinger();
574                         next = schedule_exit(next);
575                 } while (next <= 0);
576
577                 /* "next" is time to send next probe, if positive.
578                  * If next<=0 send now or as soon as possible. */
579
580                 /* Technical part. Looks wicked. Could be dropped,
581                  * if everyone used the newest kernel. :-)
582                  * Its purpose is:
583                  * 1. Provide intervals less than resolution of scheduler.
584                  *    Solution: spinning.
585                  * 2. Avoid use of poll(), when recvmsg() can provide
586                  *    timed waiting (SO_RCVTIMEO). */
587                 polling = 0;
588                 if ((options & (F_ADAPTIVE|F_FLOOD_POLL)) || next<SCHINT(interval)) {
589                         int recv_expected = in_flight();
590
591                         /* If we are here, recvmsg() is unable to wait for
592                          * required timeout. */
593                         if (1000*next <= 1000000/(int)HZ) {
594                                 /* Very short timeout... So, if we wait for
595                                  * something, we sleep for MININTERVAL.
596                                  * Otherwise, spin! */
597                                 if (recv_expected) {
598                                         next = MININTERVAL;
599                                 } else {
600                                         next = 0;
601                                         /* When spinning, no reasons to poll.
602                                          * Use nonblocking recvmsg() instead. */
603                                         polling = MSG_DONTWAIT;
604                                         /* But yield yet. */
605                                         sched_yield();
606                                 }
607                         }
608
609                         if (!polling &&
610                             ((options & (F_ADAPTIVE|F_FLOOD_POLL)) || interval)) {
611                                 struct pollfd pset;
612                                 pset.fd = icmp_sock;
613                                 pset.events = POLLIN|POLLERR;
614                                 pset.revents = 0;
615                                 if (poll(&pset, 1, next) < 1 ||
616                                     !(pset.revents&(POLLIN|POLLERR)))
617                                         continue;
618                                 polling = MSG_DONTWAIT;
619                         }
620                 }
621
622                 for (;;) {
623                         struct timeval *recv_timep = NULL;
624                         struct timeval recv_time;
625                         int not_ours = 0; /* Raw socket can receive messages
626                                            * destined to other running pings. */
627
628                         iov.iov_len = packlen;
629                         memset(&msg, 0, sizeof(msg));
630                         msg.msg_name = addrbuf;
631                         msg.msg_namelen = sizeof(addrbuf);
632                         msg.msg_iov = &iov;
633                         msg.msg_iovlen = 1;
634                         msg.msg_control = ans_data;
635                         msg.msg_controllen = sizeof(ans_data);
636
637                         cc = recvmsg(icmp_sock, &msg, polling);
638                         polling = MSG_DONTWAIT;
639
640                         if (cc < 0) {
641                                 if (errno == EAGAIN || errno == EINTR)
642                                         break;
643                                 if (!receive_error_msg()) {
644                                         if (errno) {
645                                                 perror("ping: recvmsg");
646                                                 break;
647                                         }
648                                         not_ours = 1;
649                                 }
650                         } else {
651
652 #ifdef SO_TIMESTAMP
653                                 for (c = CMSG_FIRSTHDR(&msg); c; c = CMSG_NXTHDR(&msg, c)) {
654                                         if (c->cmsg_level != SOL_SOCKET ||
655                                             c->cmsg_type != SO_TIMESTAMP)
656                                                 continue;
657                                         if (c->cmsg_len < CMSG_LEN(sizeof(struct timeval)))
658                                                 continue;
659                                         recv_timep = (struct timeval*)CMSG_DATA(c);
660                                 }
661 #endif
662
663                                 if ((options&F_LATENCY) || recv_timep == NULL) {
664                                         if ((options&F_LATENCY) ||
665                                             ioctl(icmp_sock, SIOCGSTAMP, &recv_time))
666                                                 gettimeofday(&recv_time, NULL);
667                                         recv_timep = &recv_time;
668                                 }
669
670                                 not_ours = parse_reply(&msg, cc, addrbuf, recv_timep);
671                         }
672
673                         /* See? ... someone runs another ping on this host. */
674                         if (not_ours)
675                                 install_filter();
676
677                         /* If nothing is in flight, "break" returns us to pinger. */
678                         if (in_flight() == 0)
679                                 break;
680
681                         /* Otherwise, try to recvmsg() again. recvmsg()
682                          * is nonblocking after the first iteration, so that
683                          * if nothing is queued, it will receive EAGAIN
684                          * and return to pinger. */
685                 }
686         }
687         finish();
688 }
689
690 int gather_statistics(__u8 *icmph, int icmplen,
691                       int cc, __u16 seq, int hops,
692                       int csfailed, struct timeval *tv, char *from,
693                       void (*pr_reply)(__u8 *icmph, int cc))
694 {
695         int dupflag = 0;
696         long triptime = 0;
697         __u8 *ptr = icmph + icmplen;
698
699         ++nreceived;
700         if (!csfailed)
701                 acknowledge(seq);
702
703         if (timing && cc >= 8+sizeof(struct timeval)) {
704                 struct timeval tmp_tv;
705                 memcpy(&tmp_tv, ptr, sizeof(tmp_tv));
706
707 restamp:
708                 tvsub(tv, &tmp_tv);
709                 triptime = tv->tv_sec * 1000000 + tv->tv_usec;
710                 if (triptime < 0) {
711                         fprintf(stderr, "Warning: time of day goes back (%ldus), taking countermeasures.\n", triptime);
712                         triptime = 0;
713                         if (!(options & F_LATENCY)) {
714                                 gettimeofday(tv, NULL);
715                                 options |= F_LATENCY;
716                                 goto restamp;
717                         }
718                 }
719                 if (!csfailed) {
720                         tsum += triptime;
721                         tsum2 += (long long)triptime * (long long)triptime;
722                         if (triptime < tmin)
723                                 tmin = triptime;
724                         if (triptime > tmax)
725                                 tmax = triptime;
726                         if (!rtt)
727                                 rtt = triptime*8;
728                         else
729                                 rtt += triptime-rtt/8;
730                         if (options&F_ADAPTIVE)
731                                 update_interval();
732                 }
733         }
734
735         if (csfailed) {
736                 ++nchecksum;
737                 --nreceived;
738         } else if (TST(seq % mx_dup_ck)) {
739                 ++nrepeats;
740                 --nreceived;
741                 dupflag = 1;
742         } else {
743                 SET(seq % mx_dup_ck);
744                 dupflag = 0;
745         }
746         confirm = confirm_flag;
747
748         if (options & F_QUIET)
749                 return 1;
750
751         if (options & F_FLOOD) {
752                 if (!csfailed)
753                         write(STDOUT_FILENO, "\b \b", 3);
754                 else
755                         write(STDOUT_FILENO, "\bC", 1);
756         } else {
757                 int i;
758                 __u8 *cp, *dp;
759
760                 print_timestamp();
761                 printf("%d bytes from %s:", cc, from);
762
763                 if (pr_reply)
764                         pr_reply(icmph, cc);
765
766                 if (hops >= 0)
767                         printf(" ttl=%d", hops);
768
769                 if (cc < datalen+8) {
770                         printf(" (truncated)\n");
771                         return 1;
772                 }
773                 if (timing) {
774                         if (triptime >= 100000)
775                                 printf(" time=%ld ms", triptime/1000);
776                         else if (triptime >= 10000)
777                                 printf(" time=%ld.%01ld ms", triptime/1000,
778                                        (triptime%1000)/100);
779                         else if (triptime >= 1000)
780                                 printf(" time=%ld.%02ld ms", triptime/1000,
781                                        (triptime%1000)/10);
782                         else
783                                 printf(" time=%ld.%03ld ms", triptime/1000,
784                                        triptime%1000);
785                 }
786                 if (dupflag)
787                         printf(" (DUP!)");
788                 if (csfailed)
789                         printf(" (BAD CHECKSUM!)");
790
791                 /* check the data */
792                 cp = ((u_char*)ptr) + sizeof(struct timeval);
793                 dp = &outpack[8 + sizeof(struct timeval)];
794                 for (i = sizeof(struct timeval); i < datalen; ++i, ++cp, ++dp) {
795                         if (*cp != *dp) {
796                                 printf("\nwrong data byte #%d should be 0x%x but was 0x%x",
797                                        i, *dp, *cp);
798                                 cp = (u_char*)ptr + sizeof(struct timeval);
799                                 for (i = sizeof(struct timeval); i < datalen; ++i, ++cp) {
800                                         if ((i % 32) == sizeof(struct timeval))
801                                                 printf("\n#%d\t", i);
802                                         printf("%x ", *cp);
803                                 }
804                                 break;
805                         }
806                 }
807         }
808         return 0;
809 }
810
811 static long llsqrt(long long a)
812 {
813         long long prev = ~((long long)1 << 63);
814         long long x = a;
815
816         if (x > 0) {
817                 while (x < prev) {
818                         prev = x;
819                         x = (x+(a/x))/2;
820                 }
821         }
822
823         return (long)x;
824 }
825
826 /*
827  * finish --
828  *      Print out statistics, and give up.
829  */
830 void finish(void)
831 {
832         struct timeval tv = cur_time;
833         char *comma = "";
834
835         tvsub(&tv, &start_time);
836
837         putchar('\n');
838         fflush(stdout);
839         printf("--- %s ping statistics ---\n", hostname);
840         printf("%ld packets transmitted, ", ntransmitted);
841         printf("%ld received", nreceived);
842         if (nrepeats)
843                 printf(", +%ld duplicates", nrepeats);
844         if (nchecksum)
845                 printf(", +%ld corrupted", nchecksum);
846         if (nerrors)
847                 printf(", +%ld errors", nerrors);
848         if (ntransmitted) {
849                 printf(", %d%% packet loss",
850                        (int) ((((long long)(ntransmitted - nreceived)) * 100) /
851                               ntransmitted));
852                 printf(", time %ldms", 1000*tv.tv_sec+tv.tv_usec/1000);
853         }
854         putchar('\n');
855
856         if (nreceived && timing) {
857                 long tmdev;
858
859                 tsum /= nreceived + nrepeats;
860                 tsum2 /= nreceived + nrepeats;
861                 tmdev = llsqrt(tsum2 - tsum * tsum);
862
863                 printf("rtt min/avg/max/mdev = %ld.%03ld/%lu.%03ld/%ld.%03ld/%ld.%03ld ms",
864                        (long)tmin/1000, (long)tmin%1000,
865                        (unsigned long)(tsum/1000), (long)(tsum%1000),
866                        (long)tmax/1000, (long)tmax%1000,
867                        (long)tmdev/1000, (long)tmdev%1000
868                        );
869                 comma = ", ";
870         }
871         if (pipesize > 1) {
872                 printf("%spipe %d", comma, pipesize);
873                 comma = ", ";
874         }
875         if (ntransmitted > 1 && (!interval || (options&(F_FLOOD|F_ADAPTIVE)))) {
876                 int ipg = (1000000*(long long)tv.tv_sec+tv.tv_usec)/(ntransmitted-1);
877                 printf("%sipg/ewma %d.%03d/%d.%03d ms",
878                        comma, ipg/1000, ipg%1000, rtt/8000, (rtt/8)%1000);
879         }
880         putchar('\n');
881         exit(!nreceived || (deadline && nreceived < npackets));
882 }
883
884
885 void status(void)
886 {
887         int loss = 0;
888         long tavg = 0;
889
890         status_snapshot = 0;
891
892         if (ntransmitted)
893                 loss = (((long long)(ntransmitted - nreceived)) * 100) / ntransmitted;
894
895         fprintf(stderr, "\r%ld/%ld packets, %d%% loss", ntransmitted, nreceived, loss);
896
897         if (nreceived && timing) {
898                 tavg = tsum / (nreceived + nrepeats);
899
900                 fprintf(stderr, ", min/avg/ewma/max = %ld.%03ld/%lu.%03ld/%d.%03d/%ld.%03ld ms",
901                        (long)tmin/1000, (long)tmin%1000,
902                        tavg/1000, tavg%1000,
903                        rtt/8000, (rtt/8)%1000,
904                        (long)tmax/1000, (long)tmax%1000
905                        );
906         }
907         fprintf(stderr, "\n");
908 }
909