OSDN Git Service

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