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