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