ping: implement -A "adaptive ping"
function old new delta common_ping_main 1757 1862 +105 packed_usage 32367 32427 +60 sendping_tail 236 209 -27 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/1 up/down: 165/-27) Total: 138 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
		@@ -74,6 +74,7 @@
 | 
			
		||||
//usage:	)
 | 
			
		||||
//usage:     "\n	-c CNT		Send only CNT pings"
 | 
			
		||||
//usage:     "\n	-s SIZE		Send SIZE data bytes in packets (default 56)"
 | 
			
		||||
//usage:     "\n	-A		Ping as soon as reply is recevied"
 | 
			
		||||
//usage:     "\n	-t TTL		Set TTL"
 | 
			
		||||
//usage:     "\n	-I IFACE/IP	Source interface or IP address"
 | 
			
		||||
//usage:     "\n	-W SEC		Seconds to wait for the first response (default 10)"
 | 
			
		||||
@@ -90,6 +91,7 @@
 | 
			
		||||
//usage:       "Send ICMP ECHO_REQUEST packets to network hosts\n"
 | 
			
		||||
//usage:     "\n	-c CNT		Send only CNT pings"
 | 
			
		||||
//usage:     "\n	-s SIZE		Send SIZE data bytes in packets (default 56)"
 | 
			
		||||
//usage:     "\n	-A		Ping as soon as reply is recevied"
 | 
			
		||||
//usage:     "\n	-I IFACE/IP	Source interface or IP address"
 | 
			
		||||
//usage:     "\n	-q		Quiet, only display output at start"
 | 
			
		||||
//usage:     "\n			and when finished"
 | 
			
		||||
@@ -348,20 +350,21 @@ static int common_ping_main(sa_family_t af, char **argv)
 | 
			
		||||
/* Full(er) version */
 | 
			
		||||
 | 
			
		||||
/* -c NUM, -t NUM, -w NUM, -W NUM */
 | 
			
		||||
#define OPT_STRING "qvc:+s:t:+w:+W:+I:np:4"IF_PING6("6")
 | 
			
		||||
#define OPT_STRING "qvAc:+s:t:+w:+W:+I:np:4"IF_PING6("6")
 | 
			
		||||
enum {
 | 
			
		||||
	OPT_QUIET = 1 << 0,
 | 
			
		||||
	OPT_VERBOSE = 1 << 1,
 | 
			
		||||
	OPT_c = 1 << 2,
 | 
			
		||||
	OPT_s = 1 << 3,
 | 
			
		||||
	OPT_t = 1 << 4,
 | 
			
		||||
	OPT_w = 1 << 5,
 | 
			
		||||
	OPT_W = 1 << 6,
 | 
			
		||||
	OPT_I = 1 << 7,
 | 
			
		||||
	/*OPT_n = 1 << 8, - ignored */
 | 
			
		||||
	OPT_p = 1 << 9,
 | 
			
		||||
	OPT_IPV4 = 1 << 10,
 | 
			
		||||
	OPT_IPV6 = (1 << 11) * ENABLE_PING6,
 | 
			
		||||
	OPT_A = 1 << 2,
 | 
			
		||||
	OPT_c = 1 << 3,
 | 
			
		||||
	OPT_s = 1 << 4,
 | 
			
		||||
	OPT_t = 1 << 5,
 | 
			
		||||
	OPT_w = 1 << 6,
 | 
			
		||||
	OPT_W = 1 << 7,
 | 
			
		||||
	OPT_I = 1 << 8,
 | 
			
		||||
	/*OPT_n = 1 << 9, - ignored */
 | 
			
		||||
	OPT_p = 1 << 10,
 | 
			
		||||
	OPT_IPV4 = 1 << 11,
 | 
			
		||||
	OPT_IPV6 = (1 << 12) * ENABLE_PING6,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -377,9 +380,8 @@ struct globals {
 | 
			
		||||
	uint8_t pattern;
 | 
			
		||||
	unsigned tmin, tmax; /* in us */
 | 
			
		||||
	unsigned long long tsum; /* in us, sum of all times */
 | 
			
		||||
	unsigned deadline;
 | 
			
		||||
	unsigned deadline_ms;
 | 
			
		||||
	unsigned timeout;
 | 
			
		||||
	unsigned total_secs;
 | 
			
		||||
	unsigned sizeof_rcv_packet;
 | 
			
		||||
	char *rcv_packet; /* [datalen + MAXIPLEN + MAXICMPLEN] */
 | 
			
		||||
	void *snd_packet; /* [datalen + ipv4/ipv6_const] */
 | 
			
		||||
@@ -405,9 +407,7 @@ struct globals {
 | 
			
		||||
#define tmin         (G.tmin        )
 | 
			
		||||
#define tmax         (G.tmax        )
 | 
			
		||||
#define tsum         (G.tsum        )
 | 
			
		||||
#define deadline     (G.deadline    )
 | 
			
		||||
#define timeout      (G.timeout     )
 | 
			
		||||
#define total_secs   (G.total_secs  )
 | 
			
		||||
#define hostname     (G.hostname    )
 | 
			
		||||
#define dotted       (G.dotted      )
 | 
			
		||||
#define pingaddr     (G.pingaddr    )
 | 
			
		||||
@@ -455,7 +455,7 @@ static void print_stats_and_exit(int junk UNUSED_PARAM)
 | 
			
		||||
			tmax / 1000, tmax % 1000);
 | 
			
		||||
	}
 | 
			
		||||
	/* if condition is true, exit with 1 -- 'failure' */
 | 
			
		||||
	exit(nrecv == 0 || (deadline && nrecv < pingcount));
 | 
			
		||||
	exit(nrecv == 0 || (G.deadline_ms && nrecv < pingcount));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void sendping_tail(void (*sp)(int), int size_pkt)
 | 
			
		||||
@@ -467,22 +467,23 @@ static void sendping_tail(void (*sp)(int), int size_pkt)
 | 
			
		||||
 | 
			
		||||
	size_pkt += datalen;
 | 
			
		||||
 | 
			
		||||
	if (G.deadline_ms) {
 | 
			
		||||
		unsigned n = ((unsigned)monotonic_ms()) - G.deadline_ms;
 | 
			
		||||
		if ((int)n >= 0)
 | 
			
		||||
			print_stats_and_exit(0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* sizeof(pingaddr) can be larger than real sa size, but I think
 | 
			
		||||
	 * it doesn't matter */
 | 
			
		||||
	sz = xsendto(pingsock, G.snd_packet, size_pkt, &pingaddr.sa, sizeof(pingaddr));
 | 
			
		||||
	if (sz != size_pkt)
 | 
			
		||||
		bb_error_msg_and_die(bb_msg_write_error);
 | 
			
		||||
 | 
			
		||||
	if (pingcount == 0 || deadline || G.ntransmitted < pingcount) {
 | 
			
		||||
	if (pingcount == 0 || G.ntransmitted < pingcount) {
 | 
			
		||||
		/* Didn't send all pings yet - schedule next in 1s */
 | 
			
		||||
		signal(SIGALRM, sp);
 | 
			
		||||
		if (deadline) {
 | 
			
		||||
			total_secs += PINGINTERVAL;
 | 
			
		||||
			if (total_secs >= deadline)
 | 
			
		||||
				signal(SIGALRM, print_stats_and_exit);
 | 
			
		||||
		}
 | 
			
		||||
		alarm(PINGINTERVAL);
 | 
			
		||||
	} else { /* -c NN, and all NN are sent (and no deadline) */
 | 
			
		||||
	} else { /* -c NN, and all NN are sent */
 | 
			
		||||
		/* Wait for the last ping to come back.
 | 
			
		||||
		 * -W timeout: wait for a response in seconds.
 | 
			
		||||
		 * Affects only timeout in absence of any responses,
 | 
			
		||||
@@ -632,7 +633,7 @@ static void unpack_tail(int sz, uint32_t *tp,
 | 
			
		||||
	puts(dupmsg);
 | 
			
		||||
	fflush_all();
 | 
			
		||||
}
 | 
			
		||||
static void unpack4(char *buf, int sz, struct sockaddr_in *from)
 | 
			
		||||
static int unpack4(char *buf, int sz, struct sockaddr_in *from)
 | 
			
		||||
{
 | 
			
		||||
	struct icmp *icmppkt;
 | 
			
		||||
	struct iphdr *iphdr;
 | 
			
		||||
@@ -640,7 +641,7 @@ static void unpack4(char *buf, int sz, struct sockaddr_in *from)
 | 
			
		||||
 | 
			
		||||
	/* discard if too short */
 | 
			
		||||
	if (sz < (datalen + ICMP_MINLEN))
 | 
			
		||||
		return;
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	/* check IP header */
 | 
			
		||||
	iphdr = (struct iphdr *) buf;
 | 
			
		||||
@@ -648,7 +649,7 @@ static void unpack4(char *buf, int sz, struct sockaddr_in *from)
 | 
			
		||||
	sz -= hlen;
 | 
			
		||||
	icmppkt = (struct icmp *) (buf + hlen);
 | 
			
		||||
	if (icmppkt->icmp_id != myid)
 | 
			
		||||
		return;				/* not our ping */
 | 
			
		||||
		return 0;				/* not our ping */
 | 
			
		||||
 | 
			
		||||
	if (icmppkt->icmp_type == ICMP_ECHOREPLY) {
 | 
			
		||||
		uint16_t recv_seq = ntohs(icmppkt->icmp_seq);
 | 
			
		||||
@@ -659,25 +660,28 @@ static void unpack4(char *buf, int sz, struct sockaddr_in *from)
 | 
			
		||||
		unpack_tail(sz, tp,
 | 
			
		||||
			inet_ntoa(*(struct in_addr *) &from->sin_addr.s_addr),
 | 
			
		||||
			recv_seq, iphdr->ttl);
 | 
			
		||||
	} else if (icmppkt->icmp_type != ICMP_ECHO) {
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
	if (icmppkt->icmp_type != ICMP_ECHO) {
 | 
			
		||||
		bb_error_msg("warning: got ICMP %d (%s)",
 | 
			
		||||
				icmppkt->icmp_type,
 | 
			
		||||
				icmp_type_name(icmppkt->icmp_type));
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
#if ENABLE_PING6
 | 
			
		||||
static void unpack6(char *packet, int sz, struct sockaddr_in6 *from, int hoplimit)
 | 
			
		||||
static int unpack6(char *packet, int sz, struct sockaddr_in6 *from, int hoplimit)
 | 
			
		||||
{
 | 
			
		||||
	struct icmp6_hdr *icmppkt;
 | 
			
		||||
	char buf[INET6_ADDRSTRLEN];
 | 
			
		||||
 | 
			
		||||
	/* discard if too short */
 | 
			
		||||
	if (sz < (datalen + sizeof(struct icmp6_hdr)))
 | 
			
		||||
		return;
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	icmppkt = (struct icmp6_hdr *) packet;
 | 
			
		||||
	if (icmppkt->icmp6_id != myid)
 | 
			
		||||
		return;				/* not our ping */
 | 
			
		||||
		return 0;				/* not our ping */
 | 
			
		||||
 | 
			
		||||
	if (icmppkt->icmp6_type == ICMP6_ECHO_REPLY) {
 | 
			
		||||
		uint16_t recv_seq = ntohs(icmppkt->icmp6_seq);
 | 
			
		||||
@@ -689,11 +693,14 @@ static void unpack6(char *packet, int sz, struct sockaddr_in6 *from, int hoplimi
 | 
			
		||||
			inet_ntop(AF_INET6, &from->sin6_addr,
 | 
			
		||||
					buf, sizeof(buf)),
 | 
			
		||||
			recv_seq, hoplimit);
 | 
			
		||||
	} else if (icmppkt->icmp6_type != ICMP6_ECHO_REQUEST) {
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
	if (icmppkt->icmp6_type != ICMP6_ECHO_REQUEST) {
 | 
			
		||||
		bb_error_msg("warning: got ICMP %d (%s)",
 | 
			
		||||
				icmppkt->icmp6_type,
 | 
			
		||||
				icmp6_type_name(icmppkt->icmp6_type));
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@@ -726,6 +733,7 @@ static void ping4(len_and_sockaddr *lsa)
 | 
			
		||||
	signal(SIGINT, print_stats_and_exit);
 | 
			
		||||
 | 
			
		||||
	/* start the ping's going ... */
 | 
			
		||||
 send_ping:
 | 
			
		||||
	sendping4(0);
 | 
			
		||||
 | 
			
		||||
	/* listen for replies */
 | 
			
		||||
@@ -741,9 +749,12 @@ static void ping4(len_and_sockaddr *lsa)
 | 
			
		||||
				bb_perror_msg("recvfrom");
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		unpack4(G.rcv_packet, c, &from);
 | 
			
		||||
		c = unpack4(G.rcv_packet, c, &from);
 | 
			
		||||
		if (pingcount && G.nreceived >= pingcount)
 | 
			
		||||
			break;
 | 
			
		||||
		if (c && (option_mask32 & OPT_A)) {
 | 
			
		||||
			goto send_ping;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
#if ENABLE_PING6
 | 
			
		||||
@@ -794,10 +805,6 @@ static void ping6(len_and_sockaddr *lsa)
 | 
			
		||||
 | 
			
		||||
	signal(SIGINT, print_stats_and_exit);
 | 
			
		||||
 | 
			
		||||
	/* start the ping's going ... */
 | 
			
		||||
	sendping6(0);
 | 
			
		||||
 | 
			
		||||
	/* listen for replies */
 | 
			
		||||
	msg.msg_name = &from;
 | 
			
		||||
	msg.msg_namelen = sizeof(from);
 | 
			
		||||
	msg.msg_iov = &iov;
 | 
			
		||||
@@ -805,12 +812,18 @@ static void ping6(len_and_sockaddr *lsa)
 | 
			
		||||
	msg.msg_control = control_buf;
 | 
			
		||||
	iov.iov_base = G.rcv_packet;
 | 
			
		||||
	iov.iov_len = G.sizeof_rcv_packet;
 | 
			
		||||
 | 
			
		||||
	/* start the ping's going ... */
 | 
			
		||||
 send_ping:
 | 
			
		||||
	sendping6(0);
 | 
			
		||||
 | 
			
		||||
	/* listen for replies */
 | 
			
		||||
	while (1) {
 | 
			
		||||
		int c;
 | 
			
		||||
		struct cmsghdr *mp;
 | 
			
		||||
		int hoplimit = -1;
 | 
			
		||||
		msg.msg_controllen = sizeof(control_buf);
 | 
			
		||||
 | 
			
		||||
		msg.msg_controllen = sizeof(control_buf);
 | 
			
		||||
		c = recvmsg(pingsock, &msg, 0);
 | 
			
		||||
		if (c < 0) {
 | 
			
		||||
			if (errno != EINTR)
 | 
			
		||||
@@ -827,9 +840,12 @@ static void ping6(len_and_sockaddr *lsa)
 | 
			
		||||
				move_from_unaligned_int(hoplimit, CMSG_DATA(mp));
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		unpack6(G.rcv_packet, c, &from, hoplimit);
 | 
			
		||||
		c = unpack6(G.rcv_packet, c, &from, hoplimit);
 | 
			
		||||
		if (pingcount && G.nreceived >= pingcount)
 | 
			
		||||
			break;
 | 
			
		||||
		if (c && (option_mask32 & OPT_A)) {
 | 
			
		||||
			goto send_ping;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
@@ -875,7 +891,7 @@ static int common_ping_main(int opt, char **argv)
 | 
			
		||||
			OPT_STRING
 | 
			
		||||
			/* exactly one arg; -v and -q don't mix */
 | 
			
		||||
			"\0" "=1:q--v:v--q",
 | 
			
		||||
			&pingcount, &str_s, &opt_ttl, &deadline, &timeout, &str_I, &str_p
 | 
			
		||||
			&pingcount, &str_s, &opt_ttl, &G.deadline_ms, &timeout, &str_I, &str_p
 | 
			
		||||
	);
 | 
			
		||||
	if (opt & OPT_s)
 | 
			
		||||
		datalen = xatou16(str_s); // -s
 | 
			
		||||
@@ -889,6 +905,10 @@ static int common_ping_main(int opt, char **argv)
 | 
			
		||||
	}
 | 
			
		||||
	if (opt & OPT_p)
 | 
			
		||||
		G.pattern = xstrtou_range(str_p, 16, 0, 255);
 | 
			
		||||
	if (G.deadline_ms) {
 | 
			
		||||
		unsigned d = G.deadline_ms < INT_MAX/1000 ? G.deadline_ms : INT_MAX/1000;
 | 
			
		||||
		G.deadline_ms = 1 | ((d * 1000) + monotonic_ms());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	myid = (uint16_t) getpid();
 | 
			
		||||
	hostname = argv[optind];
 | 
			
		||||
@@ -911,7 +931,7 @@ static int common_ping_main(int opt, char **argv)
 | 
			
		||||
 | 
			
		||||
	dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
 | 
			
		||||
	ping(lsa);
 | 
			
		||||
	print_stats_and_exit(EXIT_SUCCESS);
 | 
			
		||||
	print_stats_and_exit(0);
 | 
			
		||||
	/*return EXIT_SUCCESS;*/
 | 
			
		||||
}
 | 
			
		||||
#endif /* FEATURE_FANCY_PING */
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user