Blame ping_common.c

Packit Service 6f2e62
/*
Packit Service 6f2e62
 * Copyright (c) 1989 The Regents of the University of California.
Packit Service 6f2e62
 * All rights reserved.
Packit Service 6f2e62
 *
Packit Service 6f2e62
 * This code is derived from software contributed to Berkeley by
Packit Service 6f2e62
 * Mike Muuss.
Packit Service 6f2e62
 *
Packit Service 6f2e62
 * Redistribution and use in source and binary forms, with or without
Packit Service 6f2e62
 * modification, are permitted provided that the following conditions
Packit Service 6f2e62
 * are met:
Packit Service 6f2e62
 * 1. Redistributions of source code must retain the above copyright
Packit Service 6f2e62
 *    notice, this list of conditions and the following disclaimer.
Packit Service 6f2e62
 * 2. Redistributions in binary form must reproduce the above copyright
Packit Service 6f2e62
 *    notice, this list of conditions and the following disclaimer in the
Packit Service 6f2e62
 *    documentation and/or other materials provided with the distribution.
Packit Service 6f2e62
 * 3. Neither the name of the University nor the names of its contributors
Packit Service 6f2e62
 *    may be used to endorse or promote products derived from this software
Packit Service 6f2e62
 *    without specific prior written permission.
Packit Service 6f2e62
 *
Packit Service 6f2e62
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
Packit Service 6f2e62
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
Packit Service 6f2e62
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
Packit Service 6f2e62
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
Packit Service 6f2e62
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
Packit Service 6f2e62
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
Packit Service 6f2e62
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
Packit Service 6f2e62
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
Packit Service 6f2e62
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
Packit Service 6f2e62
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
Packit Service 6f2e62
 * SUCH DAMAGE.
Packit Service 6f2e62
 */
Packit Service 6f2e62
Packit Service 6f2e62
#include "ping.h"
Packit Service 6f2e62
Packit Service 6f2e62
#ifndef HZ
Packit Service 6f2e62
#define HZ sysconf(_SC_CLK_TCK)
Packit Service 6f2e62
#endif
Packit Service 6f2e62
Packit Service 6f2e62
int options;
Packit Service 6f2e62
Packit Service 6f2e62
int mark;
Packit Service 6f2e62
int sndbuf;
Packit Service 6f2e62
int ttl;
Packit Service 6f2e62
int rtt;
Packit Service 6f2e62
int rtt_addend;
Packit Service 6f2e62
__u16 acked;
Packit Service 6f2e62
Packit Service 6f2e62
unsigned char outpack[MAXPACKET];
Packit Service 6f2e62
struct rcvd_table rcvd_tbl;
Packit Service 6f2e62
Packit Service 6f2e62
/* counters */
Packit Service 6f2e62
long npackets;			/* max packets to transmit */
Packit Service 6f2e62
long nreceived;			/* # of packets we got back */
Packit Service 6f2e62
long nrepeats;			/* number of duplicates */
Packit Service 6f2e62
long ntransmitted;		/* sequence # for outbound packets = #sent */
Packit Service 6f2e62
long nchecksum;			/* replies with bad checksum */
Packit Service 6f2e62
long nerrors;			/* icmp errors */
Packit Service 6f2e62
int interval = 1000;		/* interval between packets (msec) */
Packit Service 6f2e62
int preload = 1;
Packit Service 6f2e62
int deadline = 0;		/* time to die */
Packit Service 6f2e62
int lingertime = MAXWAIT*1000;
Packit Service 6f2e62
struct timeval start_time, cur_time;
Packit Service 6f2e62
volatile int exiting;
Packit Service 6f2e62
volatile int status_snapshot;
Packit Service 6f2e62
int confirm = 0;
Packit Service 6f2e62
volatile int in_pr_addr = 0;	/* pr_addr() is executing */
Packit Service 6f2e62
jmp_buf pr_addr_jmp;
Packit Service 6f2e62
Packit Service 6f2e62
/* Stupid workarounds for bugs/missing functionality in older linuces.
Packit Service 6f2e62
 * confirm_flag fixes refusing service of kernels without MSG_CONFIRM.
Packit Service 6f2e62
 * i.e. for linux-2.2 */
Packit Service 6f2e62
int confirm_flag = MSG_CONFIRM;
Packit Service 6f2e62
Packit Service 6f2e62
/* timing */
Packit Service 6f2e62
int timing;			/* flag to do timing */
Packit Service 6f2e62
long tmin = LONG_MAX;		/* minimum round trip time */
Packit Service 6f2e62
long tmax;			/* maximum round trip time */
Packit Service 6f2e62
/* Message for rpm maintainers: have _shame_. If you want
Packit Service 6f2e62
 * to fix something send the patch to me for sanity checking.
Packit Service 6f2e62
 * "sparcfix" patch is a complete non-sense, apparenly the person
Packit Service 6f2e62
 * prepared it was stoned.
Packit Service 6f2e62
 */
Packit Service 6f2e62
long long tsum;			/* sum of all times, for doing average */
Packit Service 6f2e62
long long tsum2;
Packit Service 6f2e62
int  pipesize = -1;
Packit Service 6f2e62
Packit Service 6f2e62
int datalen = DEFDATALEN;
Packit Service 6f2e62
Packit Service 6f2e62
char *hostname;
Packit Service 6f2e62
int uid;
Packit Service 6f2e62
uid_t euid;
Packit Service 6f2e62
int ident;			/* process id to identify our packets */
Packit Service 6f2e62
Packit Service 6f2e62
static int screen_width = INT_MAX;
Packit Service 6f2e62
Packit Service 6f2e62
#define ARRAY_SIZE(a)	(sizeof(a) / sizeof(a[0]))
Packit Service 6f2e62
Packit Service 6f2e62
#ifdef CAPABILITIES
Packit Service 6f2e62
static cap_value_t cap_raw = CAP_NET_RAW;
Packit Service 6f2e62
static cap_value_t cap_admin = CAP_NET_ADMIN;
Packit Service 6f2e62
#endif
Packit Service 6f2e62
Packit Service 6f2e62
void limit_capabilities(void)
Packit Service 6f2e62
{
Packit Service 6f2e62
#ifdef CAPABILITIES
Packit Service 6f2e62
	cap_t cap_cur_p;
Packit Service 6f2e62
	cap_t cap_p;
Packit Service 6f2e62
	cap_flag_value_t cap_ok;
Packit Service 6f2e62
Packit Service 6f2e62
	cap_cur_p = cap_get_proc();
Packit Service 6f2e62
	if (!cap_cur_p) {
Packit Service 6f2e62
		perror("ping: cap_get_proc");
Packit Service 6f2e62
		exit(-1);
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	cap_p = cap_init();
Packit Service 6f2e62
	if (!cap_p) {
Packit Service 6f2e62
		perror("ping: cap_init");
Packit Service 6f2e62
		exit(-1);
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	cap_ok = CAP_CLEAR;
Packit Service 6f2e62
	cap_get_flag(cap_cur_p, CAP_NET_ADMIN, CAP_PERMITTED, &cap_ok);
Packit Service 6f2e62
Packit Service 6f2e62
	if (cap_ok != CAP_CLEAR)
Packit Service 6f2e62
		cap_set_flag(cap_p, CAP_PERMITTED, 1, &cap_admin, CAP_SET);
Packit Service 6f2e62
Packit Service 6f2e62
	cap_ok = CAP_CLEAR;
Packit Service 6f2e62
	cap_get_flag(cap_cur_p, CAP_NET_RAW, CAP_PERMITTED, &cap_ok);
Packit Service 6f2e62
Packit Service 6f2e62
	if (cap_ok != CAP_CLEAR)
Packit Service 6f2e62
		cap_set_flag(cap_p, CAP_PERMITTED, 1, &cap_raw, CAP_SET);
Packit Service 6f2e62
Packit Service 6f2e62
	if (cap_set_proc(cap_p) < 0) {
Packit Service 6f2e62
		perror("ping: cap_set_proc");
Packit Service 6f2e62
		exit(-1);
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
Packit Service 6f2e62
		perror("ping: prctl");
Packit Service 6f2e62
		exit(-1);
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	if (setuid(getuid()) < 0) {
Packit Service 6f2e62
		perror("setuid");
Packit Service 6f2e62
		exit(-1);
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	if (prctl(PR_SET_KEEPCAPS, 0) < 0) {
Packit Service 6f2e62
		perror("ping: prctl");
Packit Service 6f2e62
		exit(-1);
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	cap_free(cap_p);
Packit Service 6f2e62
	cap_free(cap_cur_p);
Packit Service 6f2e62
#endif
Packit Service 6f2e62
	uid = getuid();
Packit Service 6f2e62
	euid = geteuid();
Packit Service 6f2e62
#ifndef CAPABILITIES
Packit Service 6f2e62
	if (seteuid(uid)) {
Packit Service 6f2e62
		perror("ping: setuid");
Packit Service 6f2e62
		exit(-1);
Packit Service 6f2e62
	}
Packit Service 6f2e62
#endif
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
#ifdef CAPABILITIES
Packit Service 6f2e62
int modify_capability(cap_value_t cap, cap_flag_value_t on)
Packit Service 6f2e62
{
Packit Service 6f2e62
	cap_t cap_p = cap_get_proc();
Packit Service 6f2e62
	cap_flag_value_t cap_ok;
Packit Service 6f2e62
	int rc = -1;
Packit Service 6f2e62
Packit Service 6f2e62
	if (!cap_p) {
Packit Service 6f2e62
		perror("ping: cap_get_proc");
Packit Service 6f2e62
		goto out;
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	cap_ok = CAP_CLEAR;
Packit Service 6f2e62
	cap_get_flag(cap_p, cap, CAP_PERMITTED, &cap_ok);
Packit Service 6f2e62
	if (cap_ok == CAP_CLEAR) {
Packit Service 6f2e62
		rc = on ? -1 : 0;
Packit Service 6f2e62
		goto out;
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	cap_set_flag(cap_p, CAP_EFFECTIVE, 1, &cap, on);
Packit Service 6f2e62
Packit Service 6f2e62
	if (cap_set_proc(cap_p) < 0) {
Packit Service 6f2e62
		perror("ping: cap_set_proc");
Packit Service 6f2e62
		goto out;
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	cap_free(cap_p);
Packit Service 6f2e62
	cap_p = NULL;
Packit Service 6f2e62
Packit Service 6f2e62
	rc = 0;
Packit Service 6f2e62
out:
Packit Service 6f2e62
	if (cap_p)
Packit Service 6f2e62
		cap_free(cap_p);
Packit Service 6f2e62
	return rc;
Packit Service 6f2e62
}
Packit Service 6f2e62
#else
Packit Service 6f2e62
int modify_capability(int on)
Packit Service 6f2e62
{
Packit Service 6f2e62
	if (seteuid(on ? euid : getuid())) {
Packit Service 6f2e62
		perror("seteuid");
Packit Service 6f2e62
		return -1;
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	return 0;
Packit Service 6f2e62
}
Packit Service 6f2e62
#endif
Packit Service 6f2e62
Packit Service 6f2e62
void drop_capabilities(void)
Packit Service 6f2e62
{
Packit Service 6f2e62
#ifdef CAPABILITIES
Packit Service 6f2e62
	cap_t cap = cap_init();
Packit Service 6f2e62
	if (cap_set_proc(cap) < 0) {
Packit Service 6f2e62
		perror("ping: cap_set_proc");
Packit Service 6f2e62
		exit(-1);
Packit Service 6f2e62
	}
Packit Service 6f2e62
	cap_free(cap);
Packit Service 6f2e62
#else
Packit Service 6f2e62
	if (setuid(getuid())) {
Packit Service 6f2e62
		perror("ping: setuid");
Packit Service 6f2e62
		exit(-1);
Packit Service 6f2e62
	}
Packit Service 6f2e62
#endif
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
/* Fills all the outpack, excluding ICMP header, but _including_
Packit Service 6f2e62
 * timestamp area with supplied pattern.
Packit Service 6f2e62
 */
Packit Service 6f2e62
void fill(char *patp, void *packet, unsigned packet_size)
Packit Service 6f2e62
{
Packit Service 6f2e62
	int ii, jj, kk;
Packit Service 6f2e62
	int pat[16];
Packit Service 6f2e62
	char *cp;
Packit Service 6f2e62
	unsigned char *bp = packet+8;
Packit Service 6f2e62
Packit Service 6f2e62
#ifdef USE_IDN
Packit Service 6f2e62
	setlocale(LC_ALL, "C");
Packit Service 6f2e62
#endif
Packit Service 6f2e62
Packit Service 6f2e62
	for (cp = patp; *cp; cp++) {
Packit Service 6f2e62
		if (!isxdigit(*cp)) {
Packit Service 6f2e62
			fprintf(stderr,
Packit Service 6f2e62
				"ping: patterns must be specified as hex digits.\n");
Packit Service 6f2e62
			exit(2);
Packit Service 6f2e62
		}
Packit Service 6f2e62
	}
Packit Service 6f2e62
	ii = sscanf(patp,
Packit Service 6f2e62
	    "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
Packit Service 6f2e62
	    &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6],
Packit Service 6f2e62
	    &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12],
Packit Service 6f2e62
	    &pat[13], &pat[14], &pat[15]);
Packit Service 6f2e62
Packit Service 6f2e62
	if (ii > 0) {
Packit Service 6f2e62
		for (kk = 0; kk <= packet_size - (8 + ii); kk += ii)
Packit Service 6f2e62
			for (jj = 0; jj < ii; ++jj)
Packit Service 6f2e62
				bp[jj + kk] = pat[jj];
Packit Service 6f2e62
	}
Packit Service 6f2e62
	if (!(options & F_QUIET)) {
Packit Service 6f2e62
		printf("PATTERN: 0x");
Packit Service 6f2e62
		for (jj = 0; jj < ii; ++jj)
Packit Service 6f2e62
			printf("%02x", bp[jj] & 0xFF);
Packit Service 6f2e62
		printf("\n");
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
#ifdef USE_IDN
Packit Service 6f2e62
	setlocale(LC_ALL, "");
Packit Service 6f2e62
#endif
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
static void sigexit(int signo)
Packit Service 6f2e62
{
Packit Service 6f2e62
	exiting = 1;
Packit Service 6f2e62
	if (in_pr_addr)
Packit Service 6f2e62
		longjmp(pr_addr_jmp, 0);
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
static void sigstatus(int signo)
Packit Service 6f2e62
{
Packit Service 6f2e62
	status_snapshot = 1;
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
Packit Service 6f2e62
int __schedule_exit(int next)
Packit Service 6f2e62
{
Packit Service 6f2e62
	static unsigned long waittime;
Packit Service 6f2e62
	struct itimerval it;
Packit Service 6f2e62
Packit Service 6f2e62
	if (waittime)
Packit Service 6f2e62
		return next;
Packit Service 6f2e62
Packit Service 6f2e62
	if (nreceived) {
Packit Service 6f2e62
		waittime = 2 * tmax;
Packit Service 6f2e62
		if (waittime < 1000*interval)
Packit Service 6f2e62
			waittime = 1000*interval;
Packit Service 6f2e62
	} else
Packit Service 6f2e62
		waittime = lingertime*1000;
Packit Service 6f2e62
Packit Service 6f2e62
	if (next < 0 || next < waittime/1000)
Packit Service 6f2e62
		next = waittime/1000;
Packit Service 6f2e62
Packit Service 6f2e62
	it.it_interval.tv_sec = 0;
Packit Service 6f2e62
	it.it_interval.tv_usec = 0;
Packit Service 6f2e62
	it.it_value.tv_sec = waittime/1000000;
Packit Service 6f2e62
	it.it_value.tv_usec = waittime%1000000;
Packit Service 6f2e62
	setitimer(ITIMER_REAL, &it, NULL);
Packit Service 6f2e62
	return next;
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
static inline void update_interval(void)
Packit Service 6f2e62
{
Packit Service 6f2e62
	int est = rtt ? rtt/8 : interval*1000;
Packit Service 6f2e62
Packit Service 6f2e62
	interval = (est+rtt_addend+500)/1000;
Packit Service 6f2e62
	if (uid && interval < MINUSERINTERVAL)
Packit Service 6f2e62
		interval = MINUSERINTERVAL;
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
/*
Packit Service 6f2e62
 * Print timestamp
Packit Service 6f2e62
 */
Packit Service 6f2e62
void print_timestamp(void)
Packit Service 6f2e62
{
Packit Service 6f2e62
	if (options & F_PTIMEOFDAY) {
Packit Service 6f2e62
		struct timeval tv;
Packit Service 6f2e62
		gettimeofday(&tv, NULL);
Packit Service 6f2e62
		printf("[%lu.%06lu] ",
Packit Service 6f2e62
		       (unsigned long)tv.tv_sec, (unsigned long)tv.tv_usec);
Packit Service 6f2e62
	}
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
/*
Packit Service 6f2e62
 * pinger --
Packit Service 6f2e62
 * 	Compose and transmit an ICMP ECHO REQUEST packet.  The IP packet
Packit Service 6f2e62
 * will be added on by the kernel.  The ID field is our UNIX process ID,
Packit Service 6f2e62
 * and the sequence number is an ascending integer.  The first 8 bytes
Packit Service 6f2e62
 * of the data portion are used to hold a UNIX "timeval" struct in VAX
Packit Service 6f2e62
 * byte-order, to compute the round-trip time.
Packit Service 6f2e62
 */
Packit Service 6f2e62
int pinger(ping_func_set_st *fset, socket_st *sock)
Packit Service 6f2e62
{
Packit Service 6f2e62
	static int oom_count;
Packit Service 6f2e62
	static int tokens;
Packit Service 6f2e62
	int i;
Packit Service 6f2e62
Packit Service 6f2e62
	/* Have we already sent enough? If we have, return an arbitrary positive value. */
Packit Service 6f2e62
	if (exiting || (npackets && ntransmitted >= npackets && !deadline))
Packit Service 6f2e62
		return 1000;
Packit Service 6f2e62
Packit Service 6f2e62
	/* Check that packets < rate*time + preload */
Packit Service 6f2e62
	if (cur_time.tv_sec == 0) {
Packit Service 6f2e62
		gettimeofday(&cur_time, NULL);
Packit Service 6f2e62
		tokens = interval*(preload-1);
Packit Service 6f2e62
	} else {
Packit Service 6f2e62
		long ntokens;
Packit Service 6f2e62
		struct timeval tv;
Packit Service 6f2e62
Packit Service 6f2e62
		gettimeofday(&tv, NULL);
Packit Service 6f2e62
		ntokens = (tv.tv_sec - cur_time.tv_sec)*1000 +
Packit Service 6f2e62
			(tv.tv_usec-cur_time.tv_usec)/1000;
Packit Service 6f2e62
		if (!interval) {
Packit Service 6f2e62
			/* Case of unlimited flood is special;
Packit Service 6f2e62
			 * if we see no reply, they are limited to 100pps */
Packit Service 6f2e62
			if (ntokens < MININTERVAL && in_flight() >= preload)
Packit Service 6f2e62
				return MININTERVAL-ntokens;
Packit Service 6f2e62
		}
Packit Service 6f2e62
		ntokens += tokens;
Packit Service 6f2e62
		if (ntokens > interval*preload)
Packit Service 6f2e62
			ntokens = interval*preload;
Packit Service 6f2e62
		if (ntokens < interval)
Packit Service 6f2e62
			return interval - ntokens;
Packit Service 6f2e62
Packit Service 6f2e62
		cur_time = tv;
Packit Service 6f2e62
		tokens = ntokens - interval;
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	if (options & F_OUTSTANDING) {
Packit Service 6f2e62
		if (ntransmitted > 0 && !rcvd_test(ntransmitted)) {
Packit Service 6f2e62
			print_timestamp();
Packit Service 6f2e62
			printf("no answer yet for icmp_seq=%lu\n", (ntransmitted % MAX_DUP_CHK));
Packit Service 6f2e62
			fflush(stdout);
Packit Service 6f2e62
		}
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
resend:
Packit Service 6f2e62
	i = fset->send_probe(sock, outpack, sizeof(outpack));
Packit Service 6f2e62
Packit Service 6f2e62
	if (i == 0) {
Packit Service 6f2e62
		oom_count = 0;
Packit Service 6f2e62
		advance_ntransmitted();
Packit Service 6f2e62
		if (!(options & F_QUIET) && (options & F_FLOOD)) {
Packit Service 6f2e62
			/* Very silly, but without this output with
Packit Service 6f2e62
			 * high preload or pipe size is very confusing. */
Packit Service 6f2e62
			if ((preload < screen_width && pipesize < screen_width) ||
Packit Service 6f2e62
			    in_flight() < screen_width)
Packit Service 6f2e62
				write_stdout(".", 1);
Packit Service 6f2e62
		}
Packit Service 6f2e62
		return interval - tokens;
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	/* And handle various errors... */
Packit Service 6f2e62
	if (i > 0) {
Packit Service 6f2e62
		/* Apparently, it is some fatal bug. */
Packit Service 6f2e62
		abort();
Packit Service 6f2e62
	} else if (errno == ENOBUFS || errno == ENOMEM) {
Packit Service 6f2e62
		int nores_interval;
Packit Service 6f2e62
Packit Service 6f2e62
		/* Device queue overflow or OOM. Packet is not sent. */
Packit Service 6f2e62
		tokens = 0;
Packit Service 6f2e62
		/* Slowdown. This works only in adaptive mode (option -A) */
Packit Service 6f2e62
		rtt_addend += (rtt < 8*50000 ? rtt/8 : 50000);
Packit Service 6f2e62
		if (options&F_ADAPTIVE)
Packit Service 6f2e62
			update_interval();
Packit Service 6f2e62
		nores_interval = SCHINT(interval/2);
Packit Service 6f2e62
		if (nores_interval > 500)
Packit Service 6f2e62
			nores_interval = 500;
Packit Service 6f2e62
		oom_count++;
Packit Service 6f2e62
		if (oom_count*nores_interval < lingertime)
Packit Service 6f2e62
			return nores_interval;
Packit Service 6f2e62
		i = 0;
Packit Service 6f2e62
		/* Fall to hard error. It is to avoid complete deadlock
Packit Service 6f2e62
		 * on stuck output device even when dealine was not requested.
Packit Service 6f2e62
		 * Expected timings are screwed up in any case, but we will
Packit Service 6f2e62
		 * exit some day. :-) */
Packit Service 6f2e62
	} else if (errno == EAGAIN) {
Packit Service 6f2e62
		/* Socket buffer is full. */
Packit Service 6f2e62
		tokens += interval;
Packit Service 6f2e62
		return MININTERVAL;
Packit Service 6f2e62
	} else {
Packit Service 6f2e62
		if ((i=fset->receive_error_msg(sock)) > 0) {
Packit Service 6f2e62
			/* An ICMP error arrived. In this case, we've received
Packit Service 6f2e62
			 * an error from sendto(), but we've also received an
Packit Service 6f2e62
			 * ICMP message, which means the packet did in fact
Packit Service 6f2e62
			 * send in some capacity. So, in this odd case, report
Packit Service 6f2e62
			 * the more specific errno as the error, and treat this
Packit Service 6f2e62
			 * as a hard local error. */
Packit Service 6f2e62
			i = 0;
Packit Service 6f2e62
			goto hard_local_error;
Packit Service 6f2e62
		}
Packit Service 6f2e62
		/* Compatibility with old linuces. */
Packit Service 6f2e62
		if (i == 0 && confirm_flag && errno == EINVAL) {
Packit Service 6f2e62
			confirm_flag = 0;
Packit Service 6f2e62
			errno = 0;
Packit Service 6f2e62
		}
Packit Service 6f2e62
		if (!errno)
Packit Service 6f2e62
			goto resend;
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
hard_local_error:
Packit Service 6f2e62
	/* Hard local error. Pretend we sent packet. */
Packit Service 6f2e62
	advance_ntransmitted();
Packit Service 6f2e62
Packit Service 6f2e62
	if (i == 0 && !(options & F_QUIET)) {
Packit Service 6f2e62
		if (options & F_FLOOD)
Packit Service 6f2e62
			write_stdout("E", 1);
Packit Service 6f2e62
		else
Packit Service 6f2e62
			perror("ping: sendmsg");
Packit Service 6f2e62
	}
Packit Service 6f2e62
	tokens = 0;
Packit Service 6f2e62
	return SCHINT(interval);
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
/* Set socket buffers, "alloc" is an estimate of memory taken by single packet. */
Packit Service 6f2e62
Packit Service 6f2e62
void sock_setbufs(socket_st *sock, int alloc)
Packit Service 6f2e62
{
Packit Service 6f2e62
	int rcvbuf, hold;
Packit Service 6f2e62
	socklen_t tmplen = sizeof(hold);
Packit Service 6f2e62
Packit Service 6f2e62
	if (!sndbuf)
Packit Service 6f2e62
		sndbuf = alloc;
Packit Service 6f2e62
	setsockopt(sock->fd, SOL_SOCKET, SO_SNDBUF, (char *)&sndbuf, sizeof(sndbuf));
Packit Service 6f2e62
Packit Service 6f2e62
	rcvbuf = hold = alloc * preload;
Packit Service 6f2e62
	if (hold < 65536)
Packit Service 6f2e62
		hold = 65536;
Packit Service 6f2e62
	setsockopt(sock->fd, SOL_SOCKET, SO_RCVBUF, (char *)&hold, sizeof(hold));
Packit Service 6f2e62
	if (getsockopt(sock->fd, SOL_SOCKET, SO_RCVBUF, (char *)&hold, &tmplen) == 0) {
Packit Service 6f2e62
		if (hold < rcvbuf)
Packit Service 6f2e62
			fprintf(stderr, "WARNING: probably, rcvbuf is not enough to hold preload.\n");
Packit Service 6f2e62
	}
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
/* Protocol independent setup and parameter checks. */
Packit Service 6f2e62
Packit Service 6f2e62
void setup(socket_st *sock)
Packit Service 6f2e62
{
Packit Service 6f2e62
	int hold;
Packit Service 6f2e62
	struct timeval tv;
Packit Service 6f2e62
	sigset_t sset;
Packit Service 6f2e62
Packit Service 6f2e62
	if ((options & F_FLOOD) && !(options & F_INTERVAL))
Packit Service 6f2e62
		interval = 0;
Packit Service 6f2e62
Packit Service 6f2e62
	if (uid && interval < MINUSERINTERVAL) {
Packit Service 6f2e62
		fprintf(stderr, "ping: cannot flood; minimal interval allowed for user is %dms\n", MINUSERINTERVAL);
Packit Service 6f2e62
		exit(2);
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	if (interval >= INT_MAX/preload) {
Packit Service 6f2e62
		fprintf(stderr, "ping: illegal preload and/or interval\n");
Packit Service 6f2e62
		exit(2);
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	hold = 1;
Packit Service 6f2e62
	if (options & F_SO_DEBUG)
Packit Service 6f2e62
		setsockopt(sock->fd, SOL_SOCKET, SO_DEBUG, (char *)&hold, sizeof(hold));
Packit Service 6f2e62
	if (options & F_SO_DONTROUTE)
Packit Service 6f2e62
		setsockopt(sock->fd, SOL_SOCKET, SO_DONTROUTE, (char *)&hold, sizeof(hold));
Packit Service 6f2e62
Packit Service 6f2e62
#ifdef SO_TIMESTAMP
Packit Service 6f2e62
	if (!(options&F_LATENCY)) {
Packit Service 6f2e62
		int on = 1;
Packit Service 6f2e62
		if (setsockopt(sock->fd, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on)))
Packit Service 6f2e62
			fprintf(stderr, "Warning: no SO_TIMESTAMP support, falling back to SIOCGSTAMP\n");
Packit Service 6f2e62
	}
Packit Service 6f2e62
#endif
Packit Service 6f2e62
#ifdef SO_MARK
Packit Service 6f2e62
	if (options & F_MARK) {
Packit Service 6f2e62
		int ret;
Packit Service 6f2e62
Packit Service 6f2e62
		enable_capability_admin();
Packit Service 6f2e62
		ret = setsockopt(sock->fd, SOL_SOCKET, SO_MARK, &mark, sizeof(mark));
Packit Service 6f2e62
		disable_capability_admin();
Packit Service 6f2e62
Packit Service 6f2e62
		if (ret == -1) {
Packit Service 6f2e62
			/* we probably dont wanna exit since old kernels
Packit Service 6f2e62
			 * dont support mark ..
Packit Service 6f2e62
			*/
Packit Service 6f2e62
			fprintf(stderr, "Warning: Failed to set mark %d\n", mark);
Packit Service 6f2e62
		}
Packit Service 6f2e62
	}
Packit Service 6f2e62
#endif
Packit Service 6f2e62
Packit Service 6f2e62
	/* Set some SNDTIMEO to prevent blocking forever
Packit Service 6f2e62
	 * on sends, when device is too slow or stalls. Just put limit
Packit Service 6f2e62
	 * of one second, or "interval", if it is less.
Packit Service 6f2e62
	 */
Packit Service 6f2e62
	tv.tv_sec = 1;
Packit Service 6f2e62
	tv.tv_usec = 0;
Packit Service 6f2e62
	if (interval < 1000) {
Packit Service 6f2e62
		tv.tv_sec = 0;
Packit Service 6f2e62
		tv.tv_usec = 1000 * SCHINT(interval);
Packit Service 6f2e62
	}
Packit Service 6f2e62
	setsockopt(sock->fd, SOL_SOCKET, SO_SNDTIMEO, (char*)&tv, sizeof(tv));
Packit Service 6f2e62
Packit Service 6f2e62
	/* Set RCVTIMEO to "interval". Note, it is just an optimization
Packit Service 6f2e62
	 * allowing to avoid redundant poll(). */
Packit Service 6f2e62
	tv.tv_sec = SCHINT(interval)/1000;
Packit Service 6f2e62
	tv.tv_usec = 1000*(SCHINT(interval)%1000);
Packit Service 6f2e62
	if (setsockopt(sock->fd, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(tv)))
Packit Service 6f2e62
		options |= F_FLOOD_POLL;
Packit Service 6f2e62
Packit Service 6f2e62
	if (!(options & F_PINGFILLED)) {
Packit Service 6f2e62
		int i;
Packit Service 6f2e62
		unsigned char *p = outpack+8;
Packit Service 6f2e62
Packit Service 6f2e62
		/* Do not forget about case of small datalen,
Packit Service 6f2e62
		 * fill timestamp area too!
Packit Service 6f2e62
		 */
Packit Service 6f2e62
		for (i = 0; i < datalen; ++i)
Packit Service 6f2e62
			*p++ = i;
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	if (sock->socktype == SOCK_RAW)
Packit Service 6f2e62
		ident = htons(getpid() & 0xFFFF);
Packit Service 6f2e62
Packit Service 6f2e62
	set_signal(SIGINT, sigexit);
Packit Service 6f2e62
	set_signal(SIGALRM, sigexit);
Packit Service 6f2e62
	set_signal(SIGQUIT, sigstatus);
Packit Service 6f2e62
Packit Service 6f2e62
	sigemptyset(&sset);
Packit Service 6f2e62
	sigprocmask(SIG_SETMASK, &sset, NULL);
Packit Service 6f2e62
Packit Service 6f2e62
	gettimeofday(&start_time, NULL);
Packit Service 6f2e62
Packit Service 6f2e62
	if (deadline) {
Packit Service 6f2e62
		struct itimerval it;
Packit Service 6f2e62
Packit Service 6f2e62
		it.it_interval.tv_sec = 0;
Packit Service 6f2e62
		it.it_interval.tv_usec = 0;
Packit Service 6f2e62
		it.it_value.tv_sec = deadline;
Packit Service 6f2e62
		it.it_value.tv_usec = 0;
Packit Service 6f2e62
		setitimer(ITIMER_REAL, &it, NULL);
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	if (isatty(STDOUT_FILENO)) {
Packit Service 6f2e62
		struct winsize w;
Packit Service 6f2e62
Packit Service 6f2e62
		if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1) {
Packit Service 6f2e62
			if (w.ws_col > 0)
Packit Service 6f2e62
				screen_width = w.ws_col;
Packit Service 6f2e62
		}
Packit Service 6f2e62
	}
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
/*
Packit Service 6f2e62
 * Return 0 if pattern in payload point to be ptr did not match the pattern that was sent  
Packit Service 6f2e62
 */
Packit Service 6f2e62
int contains_pattern_in_payload(__u8 *ptr)
Packit Service 6f2e62
{
Packit Service 6f2e62
	int i;
Packit Service 6f2e62
	__u8 *cp, *dp;
Packit Service 6f2e62
 
Packit Service 6f2e62
	/* check the data */
Packit Service 6f2e62
	cp = ((u_char*)ptr) + sizeof(struct timeval);
Packit Service 6f2e62
	dp = &outpack[8 + sizeof(struct timeval)];
Packit Service 6f2e62
	for (i = sizeof(struct timeval); i < datalen; ++i, ++cp, ++dp) {
Packit Service 6f2e62
		if (*cp != *dp)
Packit Service 6f2e62
			return 0;
Packit Service 6f2e62
	}
Packit Service 6f2e62
	return 1;
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
void main_loop(ping_func_set_st *fset, socket_st *sock, __u8 *packet, int packlen)
Packit Service 6f2e62
{
Packit Service 6f2e62
	char addrbuf[128];
Packit Service 6f2e62
	char ans_data[4096];
Packit Service 6f2e62
	struct iovec iov;
Packit Service 6f2e62
	struct msghdr msg;
Packit Service 6f2e62
	struct cmsghdr *c;
Packit Service 6f2e62
	int cc;
Packit Service 6f2e62
	int next;
Packit Service 6f2e62
	int polling;
Packit Service 6f2e62
	int recv_error;
Packit Service 6f2e62
Packit Service 6f2e62
	iov.iov_base = (char *)packet;
Packit Service 6f2e62
Packit Service 6f2e62
	for (;;) {
Packit Service 6f2e62
		/* Check exit conditions. */
Packit Service 6f2e62
		if (exiting)
Packit Service 6f2e62
			break;
Packit Service 6f2e62
		if (npackets && nreceived + nerrors >= npackets)
Packit Service 6f2e62
			break;
Packit Service 6f2e62
		if (deadline && nerrors)
Packit Service 6f2e62
			break;
Packit Service 6f2e62
		/* Check for and do special actions. */
Packit Service 6f2e62
		if (status_snapshot)
Packit Service 6f2e62
			status();
Packit Service 6f2e62
Packit Service 6f2e62
		/* Send probes scheduled to this time. */
Packit Service 6f2e62
		do {
Packit Service 6f2e62
			next = pinger(fset, sock);
Packit Service 6f2e62
			next = schedule_exit(next);
Packit Service 6f2e62
		} while (next <= 0);
Packit Service 6f2e62
Packit Service 6f2e62
		/* "next" is time to send next probe, if positive.
Packit Service 6f2e62
		 * If next<=0 send now or as soon as possible. */
Packit Service 6f2e62
Packit Service 6f2e62
		/* Technical part. Looks wicked. Could be dropped,
Packit Service 6f2e62
		 * if everyone used the newest kernel. :-)
Packit Service 6f2e62
		 * Its purpose is:
Packit Service 6f2e62
		 * 1. Provide intervals less than resolution of scheduler.
Packit Service 6f2e62
		 *    Solution: spinning.
Packit Service 6f2e62
		 * 2. Avoid use of poll(), when recvmsg() can provide
Packit Service 6f2e62
		 *    timed waiting (SO_RCVTIMEO). */
Packit Service 6f2e62
		polling = 0;
Packit Service 6f2e62
		recv_error = 0;
Packit Service 6f2e62
		if ((options & (F_ADAPTIVE|F_FLOOD_POLL)) || next
Packit Service 6f2e62
			int recv_expected = in_flight();
Packit Service 6f2e62
Packit Service 6f2e62
			/* If we are here, recvmsg() is unable to wait for
Packit Service 6f2e62
			 * required timeout. */
Packit Service 6f2e62
			if (1000 % HZ == 0 ? next <= 1000 / HZ : (next < INT_MAX / HZ && next * HZ <= 1000)) {
Packit Service 6f2e62
				/* Very short timeout... So, if we wait for
Packit Service 6f2e62
				 * something, we sleep for MININTERVAL.
Packit Service 6f2e62
				 * Otherwise, spin! */
Packit Service 6f2e62
				if (recv_expected) {
Packit Service 6f2e62
					next = MININTERVAL;
Packit Service 6f2e62
				} else {
Packit Service 6f2e62
					next = 0;
Packit Service 6f2e62
					/* When spinning, no reasons to poll.
Packit Service 6f2e62
					 * Use nonblocking recvmsg() instead. */
Packit Service 6f2e62
					polling = MSG_DONTWAIT;
Packit Service 6f2e62
					/* But yield yet. */
Packit Service 6f2e62
					sched_yield();
Packit Service 6f2e62
				}
Packit Service 6f2e62
			}
Packit Service 6f2e62
Packit Service 6f2e62
			if (!polling &&
Packit Service 6f2e62
			    ((options & (F_ADAPTIVE|F_FLOOD_POLL)) || interval)) {
Packit Service 6f2e62
				struct pollfd pset;
Packit Service 6f2e62
				pset.fd = sock->fd;
Packit Service 6f2e62
				pset.events = POLLIN;
Packit Service 6f2e62
				pset.revents = 0;
Packit Service 6f2e62
				if (poll(&pset, 1, next) < 1 ||
Packit Service 6f2e62
				    !(pset.revents&(POLLIN|POLLERR)))
Packit Service 6f2e62
					continue;
Packit Service 6f2e62
				polling = MSG_DONTWAIT;
Packit Service 6f2e62
				recv_error = pset.revents&POLLERR;
Packit Service 6f2e62
			}
Packit Service 6f2e62
		}
Packit Service 6f2e62
Packit Service 6f2e62
		for (;;) {
Packit Service 6f2e62
			struct timeval *recv_timep = NULL;
Packit Service 6f2e62
			struct timeval recv_time;
Packit Service 6f2e62
			int not_ours = 0; /* Raw socket can receive messages
Packit Service 6f2e62
					   * destined to other running pings. */
Packit Service 6f2e62
Packit Service 6f2e62
			iov.iov_len = packlen;
Packit Service 6f2e62
			memset(&msg, 0, sizeof(msg));
Packit Service 6f2e62
			msg.msg_name = addrbuf;
Packit Service 6f2e62
			msg.msg_namelen = sizeof(addrbuf);
Packit Service 6f2e62
			msg.msg_iov = &iov;
Packit Service 6f2e62
			msg.msg_iovlen = 1;
Packit Service 6f2e62
			msg.msg_control = ans_data;
Packit Service 6f2e62
			msg.msg_controllen = sizeof(ans_data);
Packit Service 6f2e62
Packit Service 6f2e62
			cc = recvmsg(sock->fd, &msg, polling);
Packit Service 6f2e62
			polling = MSG_DONTWAIT;
Packit Service 6f2e62
Packit Service 6f2e62
			if (cc < 0) {
Packit Service 6f2e62
				/* If there was a POLLERR and there is no packet
Packit Service 6f2e62
				 * on the socket, try to read the error queue.
Packit Service 6f2e62
				 * Otherwise, give up.
Packit Service 6f2e62
				 */
Packit Service 6f2e62
				if ((errno == EAGAIN && !recv_error) ||
Packit Service 6f2e62
				    errno == EINTR)
Packit Service 6f2e62
					break;
Packit Service 6f2e62
				recv_error = 0;
Packit Service 6f2e62
				if (!fset->receive_error_msg(sock)) {
Packit Service 6f2e62
					if (errno) {
Packit Service 6f2e62
						perror("ping: recvmsg");
Packit Service 6f2e62
						break;
Packit Service 6f2e62
					}
Packit Service 6f2e62
					not_ours = 1;
Packit Service 6f2e62
				}
Packit Service 6f2e62
			} else {
Packit Service 6f2e62
Packit Service 6f2e62
#ifdef SO_TIMESTAMP
Packit Service 6f2e62
				for (c = CMSG_FIRSTHDR(&msg;; c; c = CMSG_NXTHDR(&msg, c)) {
Packit Service 6f2e62
					if (c->cmsg_level != SOL_SOCKET ||
Packit Service 6f2e62
					    c->cmsg_type != SO_TIMESTAMP)
Packit Service 6f2e62
						continue;
Packit Service 6f2e62
					if (c->cmsg_len < CMSG_LEN(sizeof(struct timeval)))
Packit Service 6f2e62
						continue;
Packit Service 6f2e62
					recv_timep = (struct timeval*)CMSG_DATA(c);
Packit Service 6f2e62
				}
Packit Service 6f2e62
#endif
Packit Service 6f2e62
Packit Service 6f2e62
				if ((options&F_LATENCY) || recv_timep == NULL) {
Packit Service 6f2e62
					if ((options&F_LATENCY) ||
Packit Service 6f2e62
					    ioctl(sock->fd, SIOCGSTAMP, &recv_time))
Packit Service 6f2e62
						gettimeofday(&recv_time, NULL);
Packit Service 6f2e62
					recv_timep = &recv_time;
Packit Service 6f2e62
				}
Packit Service 6f2e62
Packit Service 6f2e62
				not_ours = fset->parse_reply(sock, &msg, cc, addrbuf, recv_timep);
Packit Service 6f2e62
			}
Packit Service 6f2e62
Packit Service 6f2e62
			/* See? ... someone runs another ping on this host. */
Packit Service 6f2e62
			if (not_ours && sock->socktype == SOCK_RAW)
Packit Service 6f2e62
				fset->install_filter(sock);
Packit Service 6f2e62
Packit Service 6f2e62
			/* If nothing is in flight, "break" returns us to pinger. */
Packit Service 6f2e62
			if (in_flight() == 0)
Packit Service 6f2e62
				break;
Packit Service 6f2e62
Packit Service 6f2e62
			/* Otherwise, try to recvmsg() again. recvmsg()
Packit Service 6f2e62
			 * is nonblocking after the first iteration, so that
Packit Service 6f2e62
			 * if nothing is queued, it will receive EAGAIN
Packit Service 6f2e62
			 * and return to pinger. */
Packit Service 6f2e62
		}
Packit Service 6f2e62
	}
Packit Service 6f2e62
	finish();
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
int gather_statistics(__u8 *icmph, int icmplen,
Packit Service 6f2e62
		      int cc, __u16 seq, int hops,
Packit Service 6f2e62
		      int csfailed, struct timeval *tv, char *from,
Packit Service 6f2e62
		      void (*pr_reply)(__u8 *icmph, int cc))
Packit Service 6f2e62
{
Packit Service 6f2e62
	int dupflag = 0;
Packit Service 6f2e62
	long triptime = 0;
Packit Service 6f2e62
	__u8 *ptr = icmph + icmplen;
Packit Service 6f2e62
Packit Service 6f2e62
	++nreceived;
Packit Service 6f2e62
	if (!csfailed)
Packit Service 6f2e62
		acknowledge(seq);
Packit Service 6f2e62
Packit Service 6f2e62
	if (timing && cc >= 8+sizeof(struct timeval)) {
Packit Service 6f2e62
		struct timeval tmp_tv;
Packit Service 6f2e62
		memcpy(&tmp_tv, ptr, sizeof(tmp_tv));
Packit Service 6f2e62
Packit Service 6f2e62
restamp:
Packit Service 6f2e62
		tvsub(tv, &tmp_tv);
Packit Service 6f2e62
		triptime = tv->tv_sec * 1000000 + tv->tv_usec;
Packit Service 6f2e62
		if (triptime < 0) {
Packit Service 6f2e62
			fprintf(stderr, "Warning: time of day goes back (%ldus), taking countermeasures.\n", triptime);
Packit Service 6f2e62
			triptime = 0;
Packit Service 6f2e62
			if (!(options & F_LATENCY)) {
Packit Service 6f2e62
				gettimeofday(tv, NULL);
Packit Service 6f2e62
				options |= F_LATENCY;
Packit Service 6f2e62
				goto restamp;
Packit Service 6f2e62
			}
Packit Service 6f2e62
		}
Packit Service 6f2e62
		if (!csfailed) {
Packit Service 6f2e62
			tsum += triptime;
Packit Service 6f2e62
			tsum2 += (long long)triptime * (long long)triptime;
Packit Service 6f2e62
			if (triptime < tmin)
Packit Service 6f2e62
				tmin = triptime;
Packit Service 6f2e62
			if (triptime > tmax)
Packit Service 6f2e62
				tmax = triptime;
Packit Service 6f2e62
			if (!rtt)
Packit Service 6f2e62
				rtt = triptime*8;
Packit Service 6f2e62
			else
Packit Service 6f2e62
				rtt += triptime-rtt/8;
Packit Service 6f2e62
			if (options&F_ADAPTIVE)
Packit Service 6f2e62
				update_interval();
Packit Service 6f2e62
		}
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	if (csfailed) {
Packit Service 6f2e62
		++nchecksum;
Packit Service 6f2e62
		--nreceived;
Packit Service 6f2e62
	} else if (rcvd_test(seq)) {
Packit Service 6f2e62
		++nrepeats;
Packit Service 6f2e62
		--nreceived;
Packit Service 6f2e62
		dupflag = 1;
Packit Service 6f2e62
	} else {
Packit Service 6f2e62
		rcvd_set(seq);
Packit Service 6f2e62
		dupflag = 0;
Packit Service 6f2e62
	}
Packit Service 6f2e62
	confirm = confirm_flag;
Packit Service 6f2e62
Packit Service 6f2e62
	if (options & F_QUIET)
Packit Service 6f2e62
		return 1;
Packit Service 6f2e62
Packit Service 6f2e62
	if (options & F_FLOOD) {
Packit Service 6f2e62
		if (!csfailed)
Packit Service 6f2e62
			write_stdout("\b \b", 3);
Packit Service 6f2e62
		else
Packit Service 6f2e62
			write_stdout("\bC", 2);
Packit Service 6f2e62
	} else {
Packit Service 6f2e62
		int i;
Packit Service 6f2e62
		__u8 *cp, *dp;
Packit Service 6f2e62
Packit Service 6f2e62
		print_timestamp();
Packit Service 6f2e62
		printf("%d bytes from %s:", cc, from);
Packit Service 6f2e62
Packit Service 6f2e62
		if (pr_reply)
Packit Service 6f2e62
			pr_reply(icmph, cc);
Packit Service 6f2e62
Packit Service 6f2e62
		if (hops >= 0)
Packit Service 6f2e62
			printf(" ttl=%d", hops);
Packit Service 6f2e62
Packit Service 6f2e62
		if (cc < datalen+8) {
Packit Service 6f2e62
			printf(" (truncated)\n");
Packit Service 6f2e62
			return 1;
Packit Service 6f2e62
		}
Packit Service 6f2e62
		if (timing) {
Packit Service 6f2e62
			if (triptime >= 100000)
Packit Service 6f2e62
				printf(" time=%ld ms", (triptime+500)/1000);
Packit Service 6f2e62
			else if (triptime >= 10000)
Packit Service 6f2e62
				printf(" time=%ld.%01ld ms", triptime/1000,
Packit Service 6f2e62
				       ((triptime%1000)+50)/100);
Packit Service 6f2e62
			else if (triptime >= 1000)
Packit Service 6f2e62
				printf(" time=%ld.%02ld ms", triptime/1000,
Packit Service 6f2e62
				       ((triptime%1000)+5)/10);
Packit Service 6f2e62
			else
Packit Service 6f2e62
				printf(" time=%ld.%03ld ms", triptime/1000,
Packit Service 6f2e62
				       triptime%1000);
Packit Service 6f2e62
		}
Packit Service 6f2e62
		if (dupflag)
Packit Service 6f2e62
			printf(" (DUP!)");
Packit Service 6f2e62
		if (csfailed)
Packit Service 6f2e62
			printf(" (BAD CHECKSUM!)");
Packit Service 6f2e62
Packit Service 6f2e62
		/* check the data */
Packit Service 6f2e62
		cp = ((unsigned char*)ptr) + sizeof(struct timeval);
Packit Service 6f2e62
		dp = &outpack[8 + sizeof(struct timeval)];
Packit Service 6f2e62
		for (i = sizeof(struct timeval); i < datalen; ++i, ++cp, ++dp) {
Packit Service 6f2e62
			if (*cp != *dp) {
Packit Service 6f2e62
				printf("\nwrong data byte #%d should be 0x%x but was 0x%x",
Packit Service 6f2e62
				       i, *dp, *cp);
Packit Service 6f2e62
				cp = (unsigned char*)ptr + sizeof(struct timeval);
Packit Service 6f2e62
				for (i = sizeof(struct timeval); i < datalen; ++i, ++cp) {
Packit Service 6f2e62
					if ((i % 32) == sizeof(struct timeval))
Packit Service 6f2e62
						printf("\n#%d\t", i);
Packit Service 6f2e62
					printf("%x ", *cp);
Packit Service 6f2e62
				}
Packit Service 6f2e62
				break;
Packit Service 6f2e62
			}
Packit Service 6f2e62
		}
Packit Service 6f2e62
	}
Packit Service 6f2e62
	return 0;
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
static long llsqrt(long long a)
Packit Service 6f2e62
{
Packit Service 6f2e62
	long long prev = ~((long long)1 << 63);
Packit Service 6f2e62
	long long x = a;
Packit Service 6f2e62
Packit Service 6f2e62
	if (x > 0) {
Packit Service 6f2e62
		while (x < prev) {
Packit Service 6f2e62
			prev = x;
Packit Service 6f2e62
			x = (x+(a/x))/2;
Packit Service 6f2e62
		}
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	return (long)x;
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
/*
Packit Service 6f2e62
 * finish --
Packit Service 6f2e62
 *	Print out statistics, and give up.
Packit Service 6f2e62
 */
Packit Service 6f2e62
void finish(void)
Packit Service 6f2e62
{
Packit Service 6f2e62
	struct timeval tv = cur_time;
Packit Service 6f2e62
	char *comma = "";
Packit Service 6f2e62
Packit Service 6f2e62
	tvsub(&tv, &start_time);
Packit Service 6f2e62
Packit Service 6f2e62
	putchar('\n');
Packit Service 6f2e62
	fflush(stdout);
Packit Service 6f2e62
	printf("--- %s ping statistics ---\n", hostname);
Packit Service 6f2e62
	printf("%ld packets transmitted, ", ntransmitted);
Packit Service 6f2e62
	printf("%ld received", nreceived);
Packit Service 6f2e62
	if (nrepeats)
Packit Service 6f2e62
		printf(", +%ld duplicates", nrepeats);
Packit Service 6f2e62
	if (nchecksum)
Packit Service 6f2e62
		printf(", +%ld corrupted", nchecksum);
Packit Service 6f2e62
	if (nerrors)
Packit Service 6f2e62
		printf(", +%ld errors", nerrors);
Packit Service 6f2e62
	if (ntransmitted) {
Packit Service 6f2e62
#ifdef USE_IDN
Packit Service 6f2e62
	setlocale(LC_ALL, "C");
Packit Service 6f2e62
#endif
Packit Service 6f2e62
		printf(", %g%% packet loss",
Packit Service 6f2e62
		       (float) ((((long long)(ntransmitted - nreceived)) * 100.0) /
Packit Service 6f2e62
			      ntransmitted));
Packit Service f4d28a
		printf(", time %ldms", 1000*tv.tv_sec+(tv.tv_usec+500)/1000);
Packit Service 6f2e62
	}
Packit Service 6f2e62
	putchar('\n');
Packit Service 6f2e62
Packit Service 6f2e62
	if (nreceived && timing) {
Packit Service 6f2e62
		long tmdev;
Packit Service 6f2e62
Packit Service 6f2e62
		tsum /= nreceived + nrepeats;
Packit Service 6f2e62
		tsum2 /= nreceived + nrepeats;
Packit Service 6f2e62
		tmdev = llsqrt(tsum2 - tsum * tsum);
Packit Service 6f2e62
Packit Service 6f2e62
		printf("rtt min/avg/max/mdev = %ld.%03ld/%lu.%03ld/%ld.%03ld/%ld.%03ld ms",
Packit Service 6f2e62
		       (long)tmin/1000, (long)tmin%1000,
Packit Service 6f2e62
		       (unsigned long)(tsum/1000), (long)(tsum%1000),
Packit Service 6f2e62
		       (long)tmax/1000, (long)tmax%1000,
Packit Service 6f2e62
		       (long)tmdev/1000, (long)tmdev%1000
Packit Service 6f2e62
		       );
Packit Service 6f2e62
		comma = ", ";
Packit Service 6f2e62
	}
Packit Service 6f2e62
	if (pipesize > 1) {
Packit Service 6f2e62
		printf("%spipe %d", comma, pipesize);
Packit Service 6f2e62
		comma = ", ";
Packit Service 6f2e62
	}
Packit Service 6f2e62
	if (nreceived && (!interval || (options&(F_FLOOD|F_ADAPTIVE))) && ntransmitted > 1) {
Packit Service 6f2e62
		int ipg = (1000000*(long long)tv.tv_sec+tv.tv_usec)/(ntransmitted-1);
Packit Service 6f2e62
		printf("%sipg/ewma %d.%03d/%d.%03d ms",
Packit Service 6f2e62
		       comma, ipg/1000, ipg%1000, rtt/8000, (rtt/8)%1000);
Packit Service 6f2e62
	}
Packit Service 6f2e62
	putchar('\n');
Packit Service 6f2e62
	exit(!nreceived || (deadline && nreceived < npackets));
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
Packit Service 6f2e62
void status(void)
Packit Service 6f2e62
{
Packit Service 6f2e62
	int loss = 0;
Packit Service 6f2e62
	long tavg = 0;
Packit Service 6f2e62
Packit Service 6f2e62
	status_snapshot = 0;
Packit Service 6f2e62
Packit Service 6f2e62
	if (ntransmitted)
Packit Service 6f2e62
		loss = (((long long)(ntransmitted - nreceived)) * 100) / ntransmitted;
Packit Service 6f2e62
Packit Service 6f2e62
	fprintf(stderr, "\r%ld/%ld packets, %d%% loss", nreceived, ntransmitted, loss);
Packit Service 6f2e62
Packit Service 6f2e62
	if (nreceived && timing) {
Packit Service 6f2e62
		tavg = tsum / (nreceived + nrepeats);
Packit Service 6f2e62
Packit Service 6f2e62
		fprintf(stderr, ", min/avg/ewma/max = %ld.%03ld/%lu.%03ld/%d.%03d/%ld.%03ld ms",
Packit Service 6f2e62
		       (long)tmin/1000, (long)tmin%1000,
Packit Service 6f2e62
		       tavg/1000, tavg%1000,
Packit Service 6f2e62
		       rtt/8000, (rtt/8)%1000,
Packit Service 6f2e62
		       (long)tmax/1000, (long)tmax%1000
Packit Service 6f2e62
		       );
Packit Service 6f2e62
	}
Packit Service 6f2e62
	fprintf(stderr, "\n");
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
inline int is_ours(socket_st *sock, uint16_t id) {
Packit Service 6f2e62
       return sock->socktype == SOCK_DGRAM || id == ident;
Packit Service 6f2e62
}