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