aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2018-02-13 23:21:33 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2018-02-13 23:21:33 +0100
commit7189af847fd8a54a85f08e9bf51cd103f0d87393 (patch)
tree2329c5eb95e97de80ed0efe071539fb23a3054f8
parent4892f3a4c77fb5051d64cfc5f9056a7d6ec6cdb2 (diff)
downloadbusybox-w32-7189af847fd8a54a85f08e9bf51cd103f0d87393.tar.gz
busybox-w32-7189af847fd8a54a85f08e9bf51cd103f0d87393.tar.bz2
busybox-w32-7189af847fd8a54a85f08e9bf51cd103f0d87393.zip
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>
-rw-r--r--networking/ping.c100
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 @@
74//usage: ) 74//usage: )
75//usage: "\n -c CNT Send only CNT pings" 75//usage: "\n -c CNT Send only CNT pings"
76//usage: "\n -s SIZE Send SIZE data bytes in packets (default 56)" 76//usage: "\n -s SIZE Send SIZE data bytes in packets (default 56)"
77//usage: "\n -A Ping as soon as reply is recevied"
77//usage: "\n -t TTL Set TTL" 78//usage: "\n -t TTL Set TTL"
78//usage: "\n -I IFACE/IP Source interface or IP address" 79//usage: "\n -I IFACE/IP Source interface or IP address"
79//usage: "\n -W SEC Seconds to wait for the first response (default 10)" 80//usage: "\n -W SEC Seconds to wait for the first response (default 10)"
@@ -90,6 +91,7 @@
90//usage: "Send ICMP ECHO_REQUEST packets to network hosts\n" 91//usage: "Send ICMP ECHO_REQUEST packets to network hosts\n"
91//usage: "\n -c CNT Send only CNT pings" 92//usage: "\n -c CNT Send only CNT pings"
92//usage: "\n -s SIZE Send SIZE data bytes in packets (default 56)" 93//usage: "\n -s SIZE Send SIZE data bytes in packets (default 56)"
94//usage: "\n -A Ping as soon as reply is recevied"
93//usage: "\n -I IFACE/IP Source interface or IP address" 95//usage: "\n -I IFACE/IP Source interface or IP address"
94//usage: "\n -q Quiet, only display output at start" 96//usage: "\n -q Quiet, only display output at start"
95//usage: "\n and when finished" 97//usage: "\n and when finished"
@@ -348,20 +350,21 @@ static int common_ping_main(sa_family_t af, char **argv)
348/* Full(er) version */ 350/* Full(er) version */
349 351
350/* -c NUM, -t NUM, -w NUM, -W NUM */ 352/* -c NUM, -t NUM, -w NUM, -W NUM */
351#define OPT_STRING "qvc:+s:t:+w:+W:+I:np:4"IF_PING6("6") 353#define OPT_STRING "qvAc:+s:t:+w:+W:+I:np:4"IF_PING6("6")
352enum { 354enum {
353 OPT_QUIET = 1 << 0, 355 OPT_QUIET = 1 << 0,
354 OPT_VERBOSE = 1 << 1, 356 OPT_VERBOSE = 1 << 1,
355 OPT_c = 1 << 2, 357 OPT_A = 1 << 2,
356 OPT_s = 1 << 3, 358 OPT_c = 1 << 3,
357 OPT_t = 1 << 4, 359 OPT_s = 1 << 4,
358 OPT_w = 1 << 5, 360 OPT_t = 1 << 5,
359 OPT_W = 1 << 6, 361 OPT_w = 1 << 6,
360 OPT_I = 1 << 7, 362 OPT_W = 1 << 7,
361 /*OPT_n = 1 << 8, - ignored */ 363 OPT_I = 1 << 8,
362 OPT_p = 1 << 9, 364 /*OPT_n = 1 << 9, - ignored */
363 OPT_IPV4 = 1 << 10, 365 OPT_p = 1 << 10,
364 OPT_IPV6 = (1 << 11) * ENABLE_PING6, 366 OPT_IPV4 = 1 << 11,
367 OPT_IPV6 = (1 << 12) * ENABLE_PING6,
365}; 368};
366 369
367 370
@@ -377,9 +380,8 @@ struct globals {
377 uint8_t pattern; 380 uint8_t pattern;
378 unsigned tmin, tmax; /* in us */ 381 unsigned tmin, tmax; /* in us */
379 unsigned long long tsum; /* in us, sum of all times */ 382 unsigned long long tsum; /* in us, sum of all times */
380 unsigned deadline; 383 unsigned deadline_ms;
381 unsigned timeout; 384 unsigned timeout;
382 unsigned total_secs;
383 unsigned sizeof_rcv_packet; 385 unsigned sizeof_rcv_packet;
384 char *rcv_packet; /* [datalen + MAXIPLEN + MAXICMPLEN] */ 386 char *rcv_packet; /* [datalen + MAXIPLEN + MAXICMPLEN] */
385 void *snd_packet; /* [datalen + ipv4/ipv6_const] */ 387 void *snd_packet; /* [datalen + ipv4/ipv6_const] */
@@ -405,9 +407,7 @@ struct globals {
405#define tmin (G.tmin ) 407#define tmin (G.tmin )
406#define tmax (G.tmax ) 408#define tmax (G.tmax )
407#define tsum (G.tsum ) 409#define tsum (G.tsum )
408#define deadline (G.deadline )
409#define timeout (G.timeout ) 410#define timeout (G.timeout )
410#define total_secs (G.total_secs )
411#define hostname (G.hostname ) 411#define hostname (G.hostname )
412#define dotted (G.dotted ) 412#define dotted (G.dotted )
413#define pingaddr (G.pingaddr ) 413#define pingaddr (G.pingaddr )
@@ -455,7 +455,7 @@ static void print_stats_and_exit(int junk UNUSED_PARAM)
455 tmax / 1000, tmax % 1000); 455 tmax / 1000, tmax % 1000);
456 } 456 }
457 /* if condition is true, exit with 1 -- 'failure' */ 457 /* if condition is true, exit with 1 -- 'failure' */
458 exit(nrecv == 0 || (deadline && nrecv < pingcount)); 458 exit(nrecv == 0 || (G.deadline_ms && nrecv < pingcount));
459} 459}
460 460
461static void sendping_tail(void (*sp)(int), int size_pkt) 461static void sendping_tail(void (*sp)(int), int size_pkt)
@@ -467,22 +467,23 @@ static void sendping_tail(void (*sp)(int), int size_pkt)
467 467
468 size_pkt += datalen; 468 size_pkt += datalen;
469 469
470 if (G.deadline_ms) {
471 unsigned n = ((unsigned)monotonic_ms()) - G.deadline_ms;
472 if ((int)n >= 0)
473 print_stats_and_exit(0);
474 }
475
470 /* sizeof(pingaddr) can be larger than real sa size, but I think 476 /* sizeof(pingaddr) can be larger than real sa size, but I think
471 * it doesn't matter */ 477 * it doesn't matter */
472 sz = xsendto(pingsock, G.snd_packet, size_pkt, &pingaddr.sa, sizeof(pingaddr)); 478 sz = xsendto(pingsock, G.snd_packet, size_pkt, &pingaddr.sa, sizeof(pingaddr));
473 if (sz != size_pkt) 479 if (sz != size_pkt)
474 bb_error_msg_and_die(bb_msg_write_error); 480 bb_error_msg_and_die(bb_msg_write_error);
475 481
476 if (pingcount == 0 || deadline || G.ntransmitted < pingcount) { 482 if (pingcount == 0 || G.ntransmitted < pingcount) {
477 /* Didn't send all pings yet - schedule next in 1s */ 483 /* Didn't send all pings yet - schedule next in 1s */
478 signal(SIGALRM, sp); 484 signal(SIGALRM, sp);
479 if (deadline) {
480 total_secs += PINGINTERVAL;
481 if (total_secs >= deadline)
482 signal(SIGALRM, print_stats_and_exit);
483 }
484 alarm(PINGINTERVAL); 485 alarm(PINGINTERVAL);
485 } else { /* -c NN, and all NN are sent (and no deadline) */ 486 } else { /* -c NN, and all NN are sent */
486 /* Wait for the last ping to come back. 487 /* Wait for the last ping to come back.
487 * -W timeout: wait for a response in seconds. 488 * -W timeout: wait for a response in seconds.
488 * Affects only timeout in absence of any responses, 489 * Affects only timeout in absence of any responses,
@@ -632,7 +633,7 @@ static void unpack_tail(int sz, uint32_t *tp,
632 puts(dupmsg); 633 puts(dupmsg);
633 fflush_all(); 634 fflush_all();
634} 635}
635static void unpack4(char *buf, int sz, struct sockaddr_in *from) 636static int unpack4(char *buf, int sz, struct sockaddr_in *from)
636{ 637{
637 struct icmp *icmppkt; 638 struct icmp *icmppkt;
638 struct iphdr *iphdr; 639 struct iphdr *iphdr;
@@ -640,7 +641,7 @@ static void unpack4(char *buf, int sz, struct sockaddr_in *from)
640 641
641 /* discard if too short */ 642 /* discard if too short */
642 if (sz < (datalen + ICMP_MINLEN)) 643 if (sz < (datalen + ICMP_MINLEN))
643 return; 644 return 0;
644 645
645 /* check IP header */ 646 /* check IP header */
646 iphdr = (struct iphdr *) buf; 647 iphdr = (struct iphdr *) buf;
@@ -648,7 +649,7 @@ static void unpack4(char *buf, int sz, struct sockaddr_in *from)
648 sz -= hlen; 649 sz -= hlen;
649 icmppkt = (struct icmp *) (buf + hlen); 650 icmppkt = (struct icmp *) (buf + hlen);
650 if (icmppkt->icmp_id != myid) 651 if (icmppkt->icmp_id != myid)
651 return; /* not our ping */ 652 return 0; /* not our ping */
652 653
653 if (icmppkt->icmp_type == ICMP_ECHOREPLY) { 654 if (icmppkt->icmp_type == ICMP_ECHOREPLY) {
654 uint16_t recv_seq = ntohs(icmppkt->icmp_seq); 655 uint16_t recv_seq = ntohs(icmppkt->icmp_seq);
@@ -659,25 +660,28 @@ static void unpack4(char *buf, int sz, struct sockaddr_in *from)
659 unpack_tail(sz, tp, 660 unpack_tail(sz, tp,
660 inet_ntoa(*(struct in_addr *) &from->sin_addr.s_addr), 661 inet_ntoa(*(struct in_addr *) &from->sin_addr.s_addr),
661 recv_seq, iphdr->ttl); 662 recv_seq, iphdr->ttl);
662 } else if (icmppkt->icmp_type != ICMP_ECHO) { 663 return 1;
664 }
665 if (icmppkt->icmp_type != ICMP_ECHO) {
663 bb_error_msg("warning: got ICMP %d (%s)", 666 bb_error_msg("warning: got ICMP %d (%s)",
664 icmppkt->icmp_type, 667 icmppkt->icmp_type,
665 icmp_type_name(icmppkt->icmp_type)); 668 icmp_type_name(icmppkt->icmp_type));
666 } 669 }
670 return 0;
667} 671}
668#if ENABLE_PING6 672#if ENABLE_PING6
669static void unpack6(char *packet, int sz, struct sockaddr_in6 *from, int hoplimit) 673static int unpack6(char *packet, int sz, struct sockaddr_in6 *from, int hoplimit)
670{ 674{
671 struct icmp6_hdr *icmppkt; 675 struct icmp6_hdr *icmppkt;
672 char buf[INET6_ADDRSTRLEN]; 676 char buf[INET6_ADDRSTRLEN];
673 677
674 /* discard if too short */ 678 /* discard if too short */
675 if (sz < (datalen + sizeof(struct icmp6_hdr))) 679 if (sz < (datalen + sizeof(struct icmp6_hdr)))
676 return; 680 return 0;
677 681
678 icmppkt = (struct icmp6_hdr *) packet; 682 icmppkt = (struct icmp6_hdr *) packet;
679 if (icmppkt->icmp6_id != myid) 683 if (icmppkt->icmp6_id != myid)
680 return; /* not our ping */ 684 return 0; /* not our ping */
681 685
682 if (icmppkt->icmp6_type == ICMP6_ECHO_REPLY) { 686 if (icmppkt->icmp6_type == ICMP6_ECHO_REPLY) {
683 uint16_t recv_seq = ntohs(icmppkt->icmp6_seq); 687 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
689 inet_ntop(AF_INET6, &from->sin6_addr, 693 inet_ntop(AF_INET6, &from->sin6_addr,
690 buf, sizeof(buf)), 694 buf, sizeof(buf)),
691 recv_seq, hoplimit); 695 recv_seq, hoplimit);
692 } else if (icmppkt->icmp6_type != ICMP6_ECHO_REQUEST) { 696 return 1;
697 }
698 if (icmppkt->icmp6_type != ICMP6_ECHO_REQUEST) {
693 bb_error_msg("warning: got ICMP %d (%s)", 699 bb_error_msg("warning: got ICMP %d (%s)",
694 icmppkt->icmp6_type, 700 icmppkt->icmp6_type,
695 icmp6_type_name(icmppkt->icmp6_type)); 701 icmp6_type_name(icmppkt->icmp6_type));
696 } 702 }
703 return 0;
697} 704}
698#endif 705#endif
699 706
@@ -726,6 +733,7 @@ static void ping4(len_and_sockaddr *lsa)
726 signal(SIGINT, print_stats_and_exit); 733 signal(SIGINT, print_stats_and_exit);
727 734
728 /* start the ping's going ... */ 735 /* start the ping's going ... */
736 send_ping:
729 sendping4(0); 737 sendping4(0);
730 738
731 /* listen for replies */ 739 /* listen for replies */
@@ -741,9 +749,12 @@ static void ping4(len_and_sockaddr *lsa)
741 bb_perror_msg("recvfrom"); 749 bb_perror_msg("recvfrom");
742 continue; 750 continue;
743 } 751 }
744 unpack4(G.rcv_packet, c, &from); 752 c = unpack4(G.rcv_packet, c, &from);
745 if (pingcount && G.nreceived >= pingcount) 753 if (pingcount && G.nreceived >= pingcount)
746 break; 754 break;
755 if (c && (option_mask32 & OPT_A)) {
756 goto send_ping;
757 }
747 } 758 }
748} 759}
749#if ENABLE_PING6 760#if ENABLE_PING6
@@ -794,10 +805,6 @@ static void ping6(len_and_sockaddr *lsa)
794 805
795 signal(SIGINT, print_stats_and_exit); 806 signal(SIGINT, print_stats_and_exit);
796 807
797 /* start the ping's going ... */
798 sendping6(0);
799
800 /* listen for replies */
801 msg.msg_name = &from; 808 msg.msg_name = &from;
802 msg.msg_namelen = sizeof(from); 809 msg.msg_namelen = sizeof(from);
803 msg.msg_iov = &iov; 810 msg.msg_iov = &iov;
@@ -805,12 +812,18 @@ static void ping6(len_and_sockaddr *lsa)
805 msg.msg_control = control_buf; 812 msg.msg_control = control_buf;
806 iov.iov_base = G.rcv_packet; 813 iov.iov_base = G.rcv_packet;
807 iov.iov_len = G.sizeof_rcv_packet; 814 iov.iov_len = G.sizeof_rcv_packet;
815
816 /* start the ping's going ... */
817 send_ping:
818 sendping6(0);
819
820 /* listen for replies */
808 while (1) { 821 while (1) {
809 int c; 822 int c;
810 struct cmsghdr *mp; 823 struct cmsghdr *mp;
811 int hoplimit = -1; 824 int hoplimit = -1;
812 msg.msg_controllen = sizeof(control_buf);
813 825
826 msg.msg_controllen = sizeof(control_buf);
814 c = recvmsg(pingsock, &msg, 0); 827 c = recvmsg(pingsock, &msg, 0);
815 if (c < 0) { 828 if (c < 0) {
816 if (errno != EINTR) 829 if (errno != EINTR)
@@ -827,9 +840,12 @@ static void ping6(len_and_sockaddr *lsa)
827 move_from_unaligned_int(hoplimit, CMSG_DATA(mp)); 840 move_from_unaligned_int(hoplimit, CMSG_DATA(mp));
828 } 841 }
829 } 842 }
830 unpack6(G.rcv_packet, c, &from, hoplimit); 843 c = unpack6(G.rcv_packet, c, &from, hoplimit);
831 if (pingcount && G.nreceived >= pingcount) 844 if (pingcount && G.nreceived >= pingcount)
832 break; 845 break;
846 if (c && (option_mask32 & OPT_A)) {
847 goto send_ping;
848 }
833 } 849 }
834} 850}
835#endif 851#endif
@@ -875,7 +891,7 @@ static int common_ping_main(int opt, char **argv)
875 OPT_STRING 891 OPT_STRING
876 /* exactly one arg; -v and -q don't mix */ 892 /* exactly one arg; -v and -q don't mix */
877 "\0" "=1:q--v:v--q", 893 "\0" "=1:q--v:v--q",
878 &pingcount, &str_s, &opt_ttl, &deadline, &timeout, &str_I, &str_p 894 &pingcount, &str_s, &opt_ttl, &G.deadline_ms, &timeout, &str_I, &str_p
879 ); 895 );
880 if (opt & OPT_s) 896 if (opt & OPT_s)
881 datalen = xatou16(str_s); // -s 897 datalen = xatou16(str_s); // -s
@@ -889,6 +905,10 @@ static int common_ping_main(int opt, char **argv)
889 } 905 }
890 if (opt & OPT_p) 906 if (opt & OPT_p)
891 G.pattern = xstrtou_range(str_p, 16, 0, 255); 907 G.pattern = xstrtou_range(str_p, 16, 0, 255);
908 if (G.deadline_ms) {
909 unsigned d = G.deadline_ms < INT_MAX/1000 ? G.deadline_ms : INT_MAX/1000;
910 G.deadline_ms = 1 | ((d * 1000) + monotonic_ms());
911 }
892 912
893 myid = (uint16_t) getpid(); 913 myid = (uint16_t) getpid();
894 hostname = argv[optind]; 914 hostname = argv[optind];
@@ -911,7 +931,7 @@ static int common_ping_main(int opt, char **argv)
911 931
912 dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa); 932 dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
913 ping(lsa); 933 ping(lsa);
914 print_stats_and_exit(EXIT_SUCCESS); 934 print_stats_and_exit(0);
915 /*return EXIT_SUCCESS;*/ 935 /*return EXIT_SUCCESS;*/
916} 936}
917#endif /* FEATURE_FANCY_PING */ 937#endif /* FEATURE_FANCY_PING */