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