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