diff options
Diffstat (limited to 'networking')
-rw-r--r-- | networking/ping.c | 100 |
1 files changed, 60 insertions, 40 deletions
diff --git a/networking/ping.c b/networking/ping.c index d1d59d545..bf750d032 100644 --- a/networking/ping.c +++ b/networking/ping.c @@ -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 */ |