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