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:
parent
4892f3a4c7
commit
7189af847f
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user