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