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 */
fill(char * patp)65 static void fill(char *patp)
66 {
67 int ii, jj, kk;
68 int pat[16];
69 char *cp;
70 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
common_options(int ch)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
sigexit(int signo)228 static void sigexit(int signo)
229 {
230 exiting = 1;
231 }
232
sigstatus(int signo)233 static void sigstatus(int signo)
234 {
235 status_snapshot = 1;
236 }
237
238
__schedule_exit(int next)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
update_interval(void)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 */
pinger(void)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
sock_setbufs(int icmp_sock,int alloc)393 void sock_setbufs(int icmp_sock, int alloc)
394 {
395 int rcvbuf, hold;
396 int 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
setup(int icmp_sock)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 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 if (!ident)
477 ident = getpid() & 0xFFFF;
478
479 set_signal(SIGINT, sigexit);
480 set_signal(SIGALRM, sigexit);
481 set_signal(SIGQUIT, sigstatus);
482
483 gettimeofday(&start_time, NULL);
484
485 if (deadline) {
486 struct itimerval it;
487
488 it.it_interval.tv_sec = 0;
489 it.it_interval.tv_usec = 0;
490 it.it_value.tv_sec = deadline;
491 it.it_value.tv_usec = 0;
492 setitimer(ITIMER_REAL, &it, NULL);
493 }
494
495 #ifndef ANDROID
496 if (isatty(STDOUT_FILENO)) {
497 struct winsize w;
498
499 if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1) {
500 if (w.ws_col > 0)
501 screen_width = w.ws_col;
502 }
503 }
504 #endif
505 }
506
main_loop(int icmp_sock,__u8 * packet,int packlen)507 void main_loop(int icmp_sock, __u8 *packet, int packlen)
508 {
509 char addrbuf[128];
510 char ans_data[4096];
511 struct iovec iov;
512 struct msghdr msg;
513 struct cmsghdr *c;
514 int cc;
515 int next;
516 int polling;
517
518 iov.iov_base = (char *)packet;
519
520 for (;;) {
521 /* Check exit conditions. */
522 if (exiting)
523 break;
524 if (npackets && nreceived + nerrors >= npackets)
525 break;
526 if (deadline && nerrors)
527 break;
528 /* Check for and do special actions. */
529 if (status_snapshot)
530 status();
531
532 /* Send probes scheduled to this time. */
533 do {
534 next = pinger();
535 next = schedule_exit(next);
536 } while (next <= 0);
537
538 /* "next" is time to send next probe, if positive.
539 * If next<=0 send now or as soon as possible. */
540
541 /* Technical part. Looks wicked. Could be dropped,
542 * if everyone used the newest kernel. :-)
543 * Its purpose is:
544 * 1. Provide intervals less than resolution of scheduler.
545 * Solution: spinning.
546 * 2. Avoid use of poll(), when recvmsg() can provide
547 * timed waiting (SO_RCVTIMEO). */
548 polling = 0;
549 if ((options & (F_ADAPTIVE|F_FLOOD_POLL)) || next<SCHINT(interval)) {
550 int recv_expected = in_flight();
551
552 /* If we are here, recvmsg() is unable to wait for
553 * required timeout. */
554 if (1000*next <= 1000000/(int)HZ) {
555 /* Very short timeout... So, if we wait for
556 * something, we sleep for MININTERVAL.
557 * Otherwise, spin! */
558 if (recv_expected) {
559 next = MININTERVAL;
560 } else {
561 next = 0;
562 /* When spinning, no reasons to poll.
563 * Use nonblocking recvmsg() instead. */
564 polling = MSG_DONTWAIT;
565 /* But yield yet. */
566 sched_yield();
567 }
568 }
569
570 if (!polling &&
571 ((options & (F_ADAPTIVE|F_FLOOD_POLL)) || interval)) {
572 struct pollfd pset;
573 pset.fd = icmp_sock;
574 pset.events = POLLIN|POLLERR;
575 pset.revents = 0;
576 if (poll(&pset, 1, next) < 1 ||
577 !(pset.revents&(POLLIN|POLLERR)))
578 continue;
579 polling = MSG_DONTWAIT;
580 }
581 }
582
583 for (;;) {
584 struct timeval *recv_timep = NULL;
585 struct timeval recv_time;
586 int not_ours = 0; /* Raw socket can receive messages
587 * destined to other running pings. */
588
589 iov.iov_len = packlen;
590 msg.msg_name = addrbuf;
591 msg.msg_namelen = sizeof(addrbuf);
592 msg.msg_iov = &iov;
593 msg.msg_iovlen = 1;
594 msg.msg_control = ans_data;
595 msg.msg_controllen = sizeof(ans_data);
596
597 cc = recvmsg(icmp_sock, &msg, polling);
598 polling = MSG_DONTWAIT;
599
600 if (cc < 0) {
601 if (errno == EAGAIN || errno == EINTR)
602 break;
603 if (!receive_error_msg()) {
604 if (errno) {
605 perror("ping: recvmsg");
606 break;
607 }
608 not_ours = 1;
609 }
610 } else {
611
612 #ifdef SO_TIMESTAMP
613 for (c = CMSG_FIRSTHDR(&msg); c; c = CMSG_NXTHDR(&msg, c)) {
614 if (c->cmsg_level != SOL_SOCKET ||
615 c->cmsg_type != SO_TIMESTAMP)
616 continue;
617 if (c->cmsg_len < CMSG_LEN(sizeof(struct timeval)))
618 continue;
619 recv_timep = (struct timeval*)CMSG_DATA(c);
620 }
621 #endif
622
623 if ((options&F_LATENCY) || recv_timep == NULL) {
624 if ((options&F_LATENCY) ||
625 ioctl(icmp_sock, SIOCGSTAMP, &recv_time))
626 gettimeofday(&recv_time, NULL);
627 recv_timep = &recv_time;
628 }
629
630 not_ours = parse_reply(&msg, cc, addrbuf, recv_timep);
631 }
632
633 /* See? ... someone runs another ping on this host. */
634 if (not_ours)
635 install_filter();
636
637 /* If nothing is in flight, "break" returns us to pinger. */
638 if (in_flight() == 0)
639 break;
640
641 /* Otherwise, try to recvmsg() again. recvmsg()
642 * is nonblocking after the first iteration, so that
643 * if nothing is queued, it will receive EAGAIN
644 * and return to pinger. */
645 }
646 }
647 finish();
648 }
649
gather_statistics(__u8 * ptr,int cc,__u16 seq,int hops,int csfailed,struct timeval * tv,char * from)650 int gather_statistics(__u8 *ptr, int cc, __u16 seq, int hops,
651 int csfailed, struct timeval *tv, char *from)
652 {
653 int dupflag = 0;
654 long triptime = 0;
655
656 ++nreceived;
657 if (!csfailed)
658 acknowledge(seq);
659
660 if (timing && cc >= 8+sizeof(struct timeval)) {
661 struct timeval tmp_tv;
662 memcpy(&tmp_tv, ptr, sizeof(tmp_tv));
663
664 restamp:
665 tvsub(tv, &tmp_tv);
666 triptime = tv->tv_sec * 1000000 + tv->tv_usec;
667 if (triptime < 0) {
668 fprintf(stderr, "Warning: time of day goes back (%ldus), taking countermeasures.\n", triptime);
669 triptime = 0;
670 if (!(options & F_LATENCY)) {
671 gettimeofday(tv, NULL);
672 options |= F_LATENCY;
673 goto restamp;
674 }
675 }
676 if (!csfailed) {
677 tsum += triptime;
678 tsum2 += (long long)triptime * (long long)triptime;
679 if (triptime < tmin)
680 tmin = triptime;
681 if (triptime > tmax)
682 tmax = triptime;
683 if (!rtt)
684 rtt = triptime*8;
685 else
686 rtt += triptime-rtt/8;
687 if (options&F_ADAPTIVE)
688 update_interval();
689 }
690 }
691
692 if (csfailed) {
693 ++nchecksum;
694 --nreceived;
695 } else if (TST(seq % mx_dup_ck)) {
696 ++nrepeats;
697 --nreceived;
698 dupflag = 1;
699 } else {
700 SET(seq % mx_dup_ck);
701 dupflag = 0;
702 }
703 confirm = confirm_flag;
704
705 if (options & F_QUIET)
706 return 1;
707
708 if (options & F_FLOOD) {
709 if (!csfailed)
710 write(STDOUT_FILENO, "\b \b", 3);
711 else
712 write(STDOUT_FILENO, "\bC", 1);
713 } else {
714 int i;
715 __u8 *cp, *dp;
716 printf("%d bytes from %s: icmp_seq=%u", cc, from, seq);
717
718 if (hops >= 0)
719 printf(" ttl=%d", hops);
720
721 if (cc < datalen+8) {
722 printf(" (truncated)\n");
723 return 1;
724 }
725 if (timing) {
726 if (triptime >= 100000)
727 printf(" time=%ld ms", triptime/1000);
728 else if (triptime >= 10000)
729 printf(" time=%ld.%01ld ms", triptime/1000,
730 (triptime%1000)/100);
731 else if (triptime >= 1000)
732 printf(" time=%ld.%02ld ms", triptime/1000,
733 (triptime%1000)/10);
734 else
735 printf(" time=%ld.%03ld ms", triptime/1000,
736 triptime%1000);
737 }
738 if (dupflag)
739 printf(" (DUP!)");
740 if (csfailed)
741 printf(" (BAD CHECKSUM!)");
742
743 /* check the data */
744 cp = ((u_char*)ptr) + sizeof(struct timeval);
745 dp = &outpack[8 + sizeof(struct timeval)];
746 for (i = sizeof(struct timeval); i < datalen; ++i, ++cp, ++dp) {
747 if (*cp != *dp) {
748 printf("\nwrong data byte #%d should be 0x%x but was 0x%x",
749 i, *dp, *cp);
750 cp = (u_char*)ptr + sizeof(struct timeval);
751 for (i = sizeof(struct timeval); i < datalen; ++i, ++cp) {
752 if ((i % 32) == sizeof(struct timeval))
753 printf("\n#%d\t", i);
754 printf("%x ", *cp);
755 }
756 break;
757 }
758 }
759 }
760 return 0;
761 }
762
llsqrt(long long a)763 static long llsqrt(long long a)
764 {
765 long long prev = ~((long long)1 << 63);
766 long long x = a;
767
768 if (x > 0) {
769 while (x < prev) {
770 prev = x;
771 x = (x+(a/x))/2;
772 }
773 }
774
775 return (long)x;
776 }
777
778 /*
779 * finish --
780 * Print out statistics, and give up.
781 */
finish(void)782 void finish(void)
783 {
784 struct timeval tv = cur_time;
785
786 tvsub(&tv, &start_time);
787
788 putchar('\n');
789 fflush(stdout);
790 printf("--- %s ping statistics ---\n", hostname);
791 printf("%ld packets transmitted, ", ntransmitted);
792 printf("%ld received", nreceived);
793 if (nrepeats)
794 printf(", +%ld duplicates", nrepeats);
795 if (nchecksum)
796 printf(", +%ld corrupted", nchecksum);
797 if (nerrors)
798 printf(", +%ld errors", nerrors);
799 if (ntransmitted) {
800 printf(", %d%% packet loss",
801 (int) ((((long long)(ntransmitted - nreceived)) * 100) /
802 ntransmitted));
803 printf(", time %ldms", 1000*tv.tv_sec+tv.tv_usec/1000);
804 }
805 putchar('\n');
806
807 if (nreceived && timing) {
808 long tmdev;
809
810 tsum /= nreceived + nrepeats;
811 tsum2 /= nreceived + nrepeats;
812 tmdev = llsqrt(tsum2 - tsum * tsum);
813
814 printf("rtt min/avg/max/mdev = %ld.%03ld/%lu.%03ld/%ld.%03ld/%ld.%03ld ms",
815 tmin/1000, tmin%1000,
816 (unsigned long)(tsum/1000), (long)(tsum%1000),
817 tmax/1000, tmax%1000,
818 tmdev/1000, tmdev%1000
819 );
820 }
821 if (pipesize > 1)
822 printf(", pipe %d", pipesize);
823 if (ntransmitted > 1 && (!interval || (options&(F_FLOOD|F_ADAPTIVE)))) {
824 int ipg = (1000000*(long long)tv.tv_sec+tv.tv_usec)/(ntransmitted-1);
825 printf(", ipg/ewma %d.%03d/%d.%03d ms",
826 ipg/1000, ipg%1000, rtt/8000, (rtt/8)%1000);
827 }
828 putchar('\n');
829 exit(!nreceived || (deadline && nreceived < npackets));
830 }
831
832
status(void)833 void status(void)
834 {
835 int loss = 0;
836 long tavg = 0;
837
838 status_snapshot = 0;
839
840 if (ntransmitted)
841 loss = (((long long)(ntransmitted - nreceived)) * 100) / ntransmitted;
842
843 fprintf(stderr, "\r%ld/%ld packets, %d%% loss", ntransmitted, nreceived, loss);
844
845 if (nreceived && timing) {
846 tavg = tsum / (nreceived + nrepeats);
847
848 fprintf(stderr, ", min/avg/ewma/max = %ld.%03ld/%lu.%03ld/%d.%03d/%ld.%03ld ms",
849 tmin/1000, tmin%1000,
850 tavg/1000, tavg%1000,
851 rtt/8000, (rtt/8)%1000,
852 tmax/1000, tmax%1000
853 );
854 }
855 fprintf(stderr, "\n");
856 }
857
858