Home | History | Annotate | Download | only in ping
      1 #include "ping_common.h"
      2 #include <ctype.h>
      3 #include <sched.h>
      4 
      5 int options;
      6 
      7 int sndbuf;
      8 int ttl;
      9 int rtt;
     10 int rtt_addend;
     11 __u16 acked;
     12 
     13 int mx_dup_ck = MAX_DUP_CHK;
     14 char rcvd_tbl[MAX_DUP_CHK / 8];
     15 
     16 
     17 /* counters */
     18 long npackets;			/* max packets to transmit */
     19 long nreceived;			/* # of packets we got back */
     20 long nrepeats;			/* number of duplicates */
     21 long ntransmitted;		/* sequence # for outbound packets = #sent */
     22 long nchecksum;			/* replies with bad checksum */
     23 long nerrors;			/* icmp errors */
     24 int interval = 1000;		/* interval between packets (msec) */
     25 int preload;
     26 int deadline = 0;		/* time to die */
     27 int lingertime = MAXWAIT*1000;
     28 struct timeval start_time, cur_time;
     29 volatile int exiting;
     30 volatile int status_snapshot;
     31 int 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 */
     36 int 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] */
     39 int working_recverr;
     40 
     41 /* timing */
     42 int timing;			/* flag to do timing */
     43 long tmin = LONG_MAX;		/* minimum round trip time */
     44 long 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  */
     50 long long tsum;			/* sum of all times, for doing average */
     51 long long tsum2;
     52 int  pipesize = -1;
     53 
     54 int datalen = DEFDATALEN;
     55 
     56 char *hostname;
     57 int uid;
     58 int ident;			/* process id to identify our packets */
     59 
     60 static int screen_width = INT_MAX;
     61 
     62 /* Fills all the outpack, excluding ICMP header, but _including_
     63  * timestamp area with supplied pattern.
     64  */
     65 static 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 
     98 void 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 
    228 static void sigexit(int signo)
    229 {
    230 	exiting = 1;
    231 }
    232 
    233 static void sigstatus(int signo)
    234 {
    235 	status_snapshot = 1;
    236 }
    237 
    238 
    239 int __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 
    265 static 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  */
    282 int 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 
    319 resend:
    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 
    393 void 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 
    414 void 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 
    507 void 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 
    650 int 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 
    664 restamp:
    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 
    763 static 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  */
    782 void 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 
    833 void 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