blob: 0342e1ab8b5ddd004dc89e8cf0db834b5877abec [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 Colittieadaaea2013-07-09 17:55:43 +0900633#ifdef SO_MARK
Lorenzo Colitti313379e2013-07-11 01:07:11 +0900634 if (options & F_MARK) {
635 int ret;
636
637 enable_capability_admin();
638 ret = setsockopt(icmp_sock, SOL_SOCKET, SO_MARK, &mark, sizeof(mark));
639 disable_capability_admin();
640
641 if (ret == -1) {
642 /* we probably dont wanna exit since old kernels
643 * dont support mark ..
644 */
645 fprintf(stderr, "Warning: Failed to set mark %d\n", mark);
646 }
647 }
Lorenzo Colittieadaaea2013-07-09 17:55:43 +0900648#endif
Lorenzo Colitti313379e2013-07-11 01:07:11 +0900649
650 /* Set some SNDTIMEO to prevent blocking forever
651 * on sends, when device is too slow or stalls. Just put limit
652 * of one second, or "interval", if it is less.
653 */
654 tv.tv_sec = 1;
655 tv.tv_usec = 0;
656 if (interval < 1000) {
657 tv.tv_sec = 0;
658 tv.tv_usec = 1000 * SCHINT(interval);
659 }
660 setsockopt(icmp_sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&tv, sizeof(tv));
661
662 /* Set RCVTIMEO to "interval". Note, it is just an optimization
663 * allowing to avoid redundant poll(). */
664 tv.tv_sec = SCHINT(interval)/1000;
665 tv.tv_usec = 1000*(SCHINT(interval)%1000);
666 if (setsockopt(icmp_sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(tv)))
667 options |= F_FLOOD_POLL;
668
669 if (!(options & F_PINGFILLED)) {
670 int i;
671 u_char *p = outpack+8;
672
673 /* Do not forget about case of small datalen,
674 * fill timestamp area too!
675 */
676 for (i = 0; i < datalen; ++i)
677 *p++ = i;
678 }
679
Lorenzo Colitti5df1daf2013-07-09 17:28:09 +0900680 if (!ident)
681 ident = htons(getpid() & 0xFFFF);
Lorenzo Colitti313379e2013-07-11 01:07:11 +0900682
683 set_signal(SIGINT, sigexit);
684 set_signal(SIGALRM, sigexit);
685 set_signal(SIGQUIT, sigstatus);
686
687 sigemptyset(&sset);
688 sigprocmask(SIG_SETMASK, &sset, NULL);
689
690 gettimeofday(&start_time, NULL);
691
692 if (deadline) {
693 struct itimerval it;
694
695 it.it_interval.tv_sec = 0;
696 it.it_interval.tv_usec = 0;
697 it.it_value.tv_sec = deadline;
698 it.it_value.tv_usec = 0;
699 setitimer(ITIMER_REAL, &it, NULL);
700 }
701
702 if (isatty(STDOUT_FILENO)) {
703 struct winsize w;
704
705 if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1) {
706 if (w.ws_col > 0)
707 screen_width = w.ws_col;
708 }
709 }
710}
711
712void main_loop(int icmp_sock, __u8 *packet, int packlen)
713{
714 char addrbuf[128];
715 char ans_data[4096];
716 struct iovec iov;
717 struct msghdr msg;
718 struct cmsghdr *c;
719 int cc;
720 int next;
721 int polling;
722
723 iov.iov_base = (char *)packet;
724
725 for (;;) {
726 /* Check exit conditions. */
727 if (exiting)
728 break;
729 if (npackets && nreceived + nerrors >= npackets)
730 break;
731 if (deadline && nerrors)
732 break;
733 /* Check for and do special actions. */
734 if (status_snapshot)
735 status();
736
737 /* Send probes scheduled to this time. */
738 do {
739 next = pinger();
740 next = schedule_exit(next);
741 } while (next <= 0);
742
743 /* "next" is time to send next probe, if positive.
744 * If next<=0 send now or as soon as possible. */
745
746 /* Technical part. Looks wicked. Could be dropped,
747 * if everyone used the newest kernel. :-)
748 * Its purpose is:
749 * 1. Provide intervals less than resolution of scheduler.
750 * Solution: spinning.
751 * 2. Avoid use of poll(), when recvmsg() can provide
752 * timed waiting (SO_RCVTIMEO). */
753 polling = 0;
754 if ((options & (F_ADAPTIVE|F_FLOOD_POLL)) || next<SCHINT(interval)) {
755 int recv_expected = in_flight();
756
757 /* If we are here, recvmsg() is unable to wait for
758 * required timeout. */
759 if (1000 % HZ == 0 ? next <= 1000 / HZ : (next < INT_MAX / HZ && next * HZ <= 1000)) {
760 /* Very short timeout... So, if we wait for
761 * something, we sleep for MININTERVAL.
762 * Otherwise, spin! */
763 if (recv_expected) {
764 next = MININTERVAL;
765 } else {
766 next = 0;
767 /* When spinning, no reasons to poll.
768 * Use nonblocking recvmsg() instead. */
769 polling = MSG_DONTWAIT;
770 /* But yield yet. */
771 sched_yield();
772 }
773 }
774
775 if (!polling &&
776 ((options & (F_ADAPTIVE|F_FLOOD_POLL)) || interval)) {
777 struct pollfd pset;
778 pset.fd = icmp_sock;
779 pset.events = POLLIN|POLLERR;
780 pset.revents = 0;
781 if (poll(&pset, 1, next) < 1 ||
782 !(pset.revents&(POLLIN|POLLERR)))
783 continue;
784 polling = MSG_DONTWAIT;
785 }
786 }
787
788 for (;;) {
789 struct timeval *recv_timep = NULL;
790 struct timeval recv_time;
791 int not_ours = 0; /* Raw socket can receive messages
792 * destined to other running pings. */
793
794 iov.iov_len = packlen;
795 memset(&msg, 0, sizeof(msg));
796 msg.msg_name = addrbuf;
797 msg.msg_namelen = sizeof(addrbuf);
798 msg.msg_iov = &iov;
799 msg.msg_iovlen = 1;
800 msg.msg_control = ans_data;
801 msg.msg_controllen = sizeof(ans_data);
802
803 cc = recvmsg(icmp_sock, &msg, polling);
804 polling = MSG_DONTWAIT;
805
806 if (cc < 0) {
807 if (errno == EAGAIN || errno == EINTR)
808 break;
809 if (!receive_error_msg()) {
810 if (errno) {
811 perror("ping: recvmsg");
812 break;
813 }
814 not_ours = 1;
815 }
816 } else {
817
818#ifdef SO_TIMESTAMP
819 for (c = CMSG_FIRSTHDR(&msg); c; c = CMSG_NXTHDR(&msg, c)) {
820 if (c->cmsg_level != SOL_SOCKET ||
821 c->cmsg_type != SO_TIMESTAMP)
822 continue;
823 if (c->cmsg_len < CMSG_LEN(sizeof(struct timeval)))
824 continue;
825 recv_timep = (struct timeval*)CMSG_DATA(c);
826 }
827#endif
828
829 if ((options&F_LATENCY) || recv_timep == NULL) {
830 if ((options&F_LATENCY) ||
831 ioctl(icmp_sock, SIOCGSTAMP, &recv_time))
832 gettimeofday(&recv_time, NULL);
833 recv_timep = &recv_time;
834 }
835
836 not_ours = parse_reply(&msg, cc, addrbuf, recv_timep);
837 }
838
839 /* See? ... someone runs another ping on this host. */
840 if (not_ours)
841 install_filter();
842
843 /* If nothing is in flight, "break" returns us to pinger. */
844 if (in_flight() == 0)
845 break;
846
847 /* Otherwise, try to recvmsg() again. recvmsg()
848 * is nonblocking after the first iteration, so that
849 * if nothing is queued, it will receive EAGAIN
850 * and return to pinger. */
851 }
852 }
853 finish();
854}
855
856int gather_statistics(__u8 *icmph, int icmplen,
857 int cc, __u16 seq, int hops,
858 int csfailed, struct timeval *tv, char *from,
859 void (*pr_reply)(__u8 *icmph, int cc))
860{
861 int dupflag = 0;
862 long triptime = 0;
863 __u8 *ptr = icmph + icmplen;
864
865 ++nreceived;
866 if (!csfailed)
867 acknowledge(seq);
868
869 if (timing && cc >= 8+sizeof(struct timeval)) {
870 struct timeval tmp_tv;
871 memcpy(&tmp_tv, ptr, sizeof(tmp_tv));
872
873restamp:
874 tvsub(tv, &tmp_tv);
875 triptime = tv->tv_sec * 1000000 + tv->tv_usec;
876 if (triptime < 0) {
877 fprintf(stderr, "Warning: time of day goes back (%ldus), taking countermeasures.\n", triptime);
878 triptime = 0;
879 if (!(options & F_LATENCY)) {
880 gettimeofday(tv, NULL);
881 options |= F_LATENCY;
882 goto restamp;
883 }
884 }
885 if (!csfailed) {
886 tsum += triptime;
887 tsum2 += (long long)triptime * (long long)triptime;
888 if (triptime < tmin)
889 tmin = triptime;
890 if (triptime > tmax)
891 tmax = triptime;
892 if (!rtt)
893 rtt = triptime*8;
894 else
895 rtt += triptime-rtt/8;
896 if (options&F_ADAPTIVE)
897 update_interval();
898 }
899 }
900
901 if (csfailed) {
902 ++nchecksum;
903 --nreceived;
904 } else if (rcvd_test(seq)) {
905 ++nrepeats;
906 --nreceived;
907 dupflag = 1;
908 } else {
909 rcvd_set(seq);
910 dupflag = 0;
911 }
912 confirm = confirm_flag;
913
914 if (options & F_QUIET)
915 return 1;
916
917 if (options & F_FLOOD) {
918 if (!csfailed)
919 write_stdout("\b \b", 3);
920 else
921 write_stdout("\bC", 2);
922 } else {
923 int i;
924 __u8 *cp, *dp;
925
926 print_timestamp();
927 printf("%d bytes from %s:", cc, from);
928
929 if (pr_reply)
930 pr_reply(icmph, cc);
931
932 if (hops >= 0)
933 printf(" ttl=%d", hops);
934
935 if (cc < datalen+8) {
936 printf(" (truncated)\n");
937 return 1;
938 }
939 if (timing) {
940 if (triptime >= 100000)
941 printf(" time=%ld ms", triptime/1000);
942 else if (triptime >= 10000)
943 printf(" time=%ld.%01ld ms", triptime/1000,
944 (triptime%1000)/100);
945 else if (triptime >= 1000)
946 printf(" time=%ld.%02ld ms", triptime/1000,
947 (triptime%1000)/10);
948 else
949 printf(" time=%ld.%03ld ms", triptime/1000,
950 triptime%1000);
951 }
952 if (dupflag)
953 printf(" (DUP!)");
954 if (csfailed)
955 printf(" (BAD CHECKSUM!)");
956
957 /* check the data */
958 cp = ((u_char*)ptr) + sizeof(struct timeval);
959 dp = &outpack[8 + sizeof(struct timeval)];
960 for (i = sizeof(struct timeval); i < datalen; ++i, ++cp, ++dp) {
961 if (*cp != *dp) {
962 printf("\nwrong data byte #%d should be 0x%x but was 0x%x",
963 i, *dp, *cp);
964 cp = (u_char*)ptr + sizeof(struct timeval);
965 for (i = sizeof(struct timeval); i < datalen; ++i, ++cp) {
966 if ((i % 32) == sizeof(struct timeval))
967 printf("\n#%d\t", i);
968 printf("%x ", *cp);
969 }
970 break;
971 }
972 }
973 }
974 return 0;
975}
976
977static long llsqrt(long long a)
978{
979 long long prev = ~((long long)1 << 63);
980 long long x = a;
981
982 if (x > 0) {
983 while (x < prev) {
984 prev = x;
985 x = (x+(a/x))/2;
986 }
987 }
988
989 return (long)x;
990}
991
992/*
993 * finish --
994 * Print out statistics, and give up.
995 */
996void finish(void)
997{
998 struct timeval tv = cur_time;
999 char *comma = "";
1000
1001 tvsub(&tv, &start_time);
1002
1003 putchar('\n');
1004 fflush(stdout);
1005 printf("--- %s ping statistics ---\n", hostname);
1006 printf("%ld packets transmitted, ", ntransmitted);
1007 printf("%ld received", nreceived);
1008 if (nrepeats)
1009 printf(", +%ld duplicates", nrepeats);
1010 if (nchecksum)
1011 printf(", +%ld corrupted", nchecksum);
1012 if (nerrors)
1013 printf(", +%ld errors", nerrors);
1014 if (ntransmitted) {
1015 printf(", %d%% packet loss",
1016 (int) ((((long long)(ntransmitted - nreceived)) * 100) /
1017 ntransmitted));
1018 printf(", time %ldms", 1000*tv.tv_sec+tv.tv_usec/1000);
1019 }
1020 putchar('\n');
1021
1022 if (nreceived && timing) {
1023 long tmdev;
1024
1025 tsum /= nreceived + nrepeats;
1026 tsum2 /= nreceived + nrepeats;
1027 tmdev = llsqrt(tsum2 - tsum * tsum);
1028
1029 printf("rtt min/avg/max/mdev = %ld.%03ld/%lu.%03ld/%ld.%03ld/%ld.%03ld ms",
1030 (long)tmin/1000, (long)tmin%1000,
1031 (unsigned long)(tsum/1000), (long)(tsum%1000),
1032 (long)tmax/1000, (long)tmax%1000,
1033 (long)tmdev/1000, (long)tmdev%1000
1034 );
1035 comma = ", ";
1036 }
1037 if (pipesize > 1) {
1038 printf("%spipe %d", comma, pipesize);
1039 comma = ", ";
1040 }
1041 if (nreceived && (!interval || (options&(F_FLOOD|F_ADAPTIVE))) && ntransmitted > 1) {
1042 int ipg = (1000000*(long long)tv.tv_sec+tv.tv_usec)/(ntransmitted-1);
1043 printf("%sipg/ewma %d.%03d/%d.%03d ms",
1044 comma, ipg/1000, ipg%1000, rtt/8000, (rtt/8)%1000);
1045 }
1046 putchar('\n');
1047 exit(!nreceived || (deadline && nreceived < npackets));
1048}
1049
1050
1051void status(void)
1052{
1053 int loss = 0;
1054 long tavg = 0;
1055
1056 status_snapshot = 0;
1057
1058 if (ntransmitted)
1059 loss = (((long long)(ntransmitted - nreceived)) * 100) / ntransmitted;
1060
1061 fprintf(stderr, "\r%ld/%ld packets, %d%% loss", ntransmitted, nreceived, loss);
1062
1063 if (nreceived && timing) {
1064 tavg = tsum / (nreceived + nrepeats);
1065
1066 fprintf(stderr, ", min/avg/ewma/max = %ld.%03ld/%lu.%03ld/%d.%03d/%ld.%03ld ms",
1067 (long)tmin/1000, (long)tmin%1000,
1068 tavg/1000, tavg%1000,
1069 rtt/8000, (rtt/8)%1000,
1070 (long)tmax/1000, (long)tmax%1000
1071 );
1072 }
1073 fprintf(stderr, "\n");
1074}
1075