aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2011-05-05 02:31:30 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2011-05-05 02:31:30 +0200
commita348b4557d3d0af411135c23448a2c5a7cd82982 (patch)
tree84eecc099d0705991939fed91c278ce8b65e350d
parentd3e4be3ccb1506cfabecc4c2f0baeb07fdd06723 (diff)
downloadbusybox-w32-a348b4557d3d0af411135c23448a2c5a7cd82982.tar.gz
busybox-w32-a348b4557d3d0af411135c23448a2c5a7cd82982.tar.bz2
busybox-w32-a348b4557d3d0af411135c23448a2c5a7cd82982.zip
traceroute: properly reduce poll timeout
This removes the problem where during the time we wait to declare a target as unresponsive we receive an unrelated ICMP packet. If there is enough traffic, this can make traceroute hang as it never declares the target as unresponsive. function old new delta common_traceroute_main 4196 4261 +65 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--networking/traceroute.c61
1 files changed, 37 insertions, 24 deletions
diff --git a/networking/traceroute.c b/networking/traceroute.c
index 96f9d3472..85181ab8d 100644
--- a/networking/traceroute.c
+++ b/networking/traceroute.c
@@ -398,18 +398,23 @@ static len_and_sockaddr* dup_sockaddr(const len_and_sockaddr *lsa)
398 398
399 399
400static int 400static int
401wait_for_reply(len_and_sockaddr *from_lsa, struct sockaddr *to) 401wait_for_reply(len_and_sockaddr *from_lsa, struct sockaddr *to, unsigned *timestamp_us, int *left_ms)
402{ 402{
403 struct pollfd pfd[1]; 403 struct pollfd pfd[1];
404 int read_len = 0; 404 int read_len = 0;
405 405
406 pfd[0].fd = rcvsock; 406 pfd[0].fd = rcvsock;
407 pfd[0].events = POLLIN; 407 pfd[0].events = POLLIN;
408 if (safe_poll(pfd, 1, waittime * 1000) > 0) { 408 if (*left_ms >= 0 && safe_poll(pfd, 1, *left_ms) > 0) {
409 unsigned t;
410
409 read_len = recv_from_to(rcvsock, 411 read_len = recv_from_to(rcvsock,
410 recv_pkt, sizeof(recv_pkt), 412 recv_pkt, sizeof(recv_pkt),
411 /*flags:*/ 0, 413 /*flags:*/ MSG_DONTWAIT,
412 &from_lsa->u.sa, to, from_lsa->len); 414 &from_lsa->u.sa, to, from_lsa->len);
415 t = monotonic_us();
416 *left_ms -= (t - *timestamp_us) / 1000;
417 *timestamp_us = t;
413 } 418 }
414 419
415 return read_len; 420 return read_len;
@@ -730,7 +735,7 @@ packet_ok(int read_len, len_and_sockaddr *from_lsa,
730 type, pr_type(type), icp->icmp6_code); 735 type, pr_type(type), icp->icmp6_code);
731 736
732 read_len -= sizeof(struct icmp6_hdr); 737 read_len -= sizeof(struct icmp6_hdr);
733 for (i = 0; i < read_len ; i++) { 738 for (i = 0; i < read_len; i++) {
734 if (i % 16 == 0) 739 if (i % 16 == 0)
735 printf("%04x:", i); 740 printf("%04x:", i);
736 if (i % 4 == 0) 741 if (i % 4 == 0)
@@ -819,7 +824,6 @@ print_delta_ms(unsigned t1p, unsigned t2p)
819static int 824static int
820common_traceroute_main(int op, char **argv) 825common_traceroute_main(int op, char **argv)
821{ 826{
822 int i;
823 int minpacket; 827 int minpacket;
824 int tos = 0; 828 int tos = 0;
825 int max_ttl = 30; 829 int max_ttl = 30;
@@ -973,6 +977,7 @@ common_traceroute_main(int op, char **argv)
973#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE && defined IP_OPTIONS 977#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE && defined IP_OPTIONS
974 if (lsrr > 0) { 978 if (lsrr > 0) {
975 unsigned char optlist[MAX_IPOPTLEN]; 979 unsigned char optlist[MAX_IPOPTLEN];
980 unsigned size;
976 981
977 /* final hop */ 982 /* final hop */
978 gwlist[lsrr] = dest_lsa->u.sin.sin_addr.s_addr; 983 gwlist[lsrr] = dest_lsa->u.sin.sin_addr.s_addr;
@@ -982,14 +987,14 @@ common_traceroute_main(int op, char **argv)
982 optlist[0] = IPOPT_NOP; 987 optlist[0] = IPOPT_NOP;
983 /* loose source route option */ 988 /* loose source route option */
984 optlist[1] = IPOPT_LSRR; 989 optlist[1] = IPOPT_LSRR;
985 i = lsrr * sizeof(gwlist[0]); 990 size = lsrr * sizeof(gwlist[0]);
986 optlist[2] = i + 3; 991 optlist[2] = size + 3;
987 /* pointer to LSRR addresses */ 992 /* pointer to LSRR addresses */
988 optlist[3] = IPOPT_MINOFF; 993 optlist[3] = IPOPT_MINOFF;
989 memcpy(optlist + 4, gwlist, i); 994 memcpy(optlist + 4, gwlist, size);
990 995
991 if (setsockopt(sndsock, IPPROTO_IP, IP_OPTIONS, 996 if (setsockopt(sndsock, IPPROTO_IP, IP_OPTIONS,
992 (char *)optlist, i + sizeof(gwlist[0])) < 0) { 997 (char *)optlist, size + sizeof(gwlist[0])) < 0) {
993 bb_perror_msg_and_die("IP_OPTIONS"); 998 bb_perror_msg_and_die("IP_OPTIONS");
994 } 999 }
995 } 1000 }
@@ -1103,28 +1108,34 @@ common_traceroute_main(int op, char **argv)
1103 int unreachable = 0; /* counter */ 1108 int unreachable = 0; /* counter */
1104 int gotlastaddr = 0; /* flags */ 1109 int gotlastaddr = 0; /* flags */
1105 int got_there = 0; 1110 int got_there = 0;
1106 int first = 1;
1107 1111
1108 printf("%2d", ttl); 1112 printf("%2d", ttl);
1109 for (probe = 0; probe < nprobes; ++probe) { 1113 for (probe = 0; probe < nprobes; ++probe) {
1110 int read_len; 1114 int read_len;
1111 unsigned t1; 1115 unsigned t1;
1112 unsigned t2; 1116 unsigned t2;
1117 int left_ms;
1113 struct ip *ip; 1118 struct ip *ip;
1114 1119
1115 if (!first && pausemsecs > 0)
1116 usleep(pausemsecs * 1000);
1117 fflush_all(); 1120 fflush_all();
1121 if (probe != 0 && pausemsecs > 0)
1122 usleep(pausemsecs * 1000);
1118 1123
1119 t1 = monotonic_us();
1120 send_probe(++seq, ttl); 1124 send_probe(++seq, ttl);
1125 t2 = t1 = monotonic_us();
1126
1127 left_ms = waittime * 1000;
1128 while ((read_len = wait_for_reply(from_lsa, to, &t2, &left_ms)) != 0) {
1129 int icmp_code;
1130
1131 /* Recv'ed a packet, or read error */
1132 /* t2 = monotonic_us() - set by wait_for_reply */
1121 1133
1122 first = 0; 1134 if (read_len < 0)
1123 while ((read_len = wait_for_reply(from_lsa, to)) != 0) { 1135 continue;
1124 t2 = monotonic_us(); 1136 icmp_code = packet_ok(read_len, from_lsa, to, seq);
1125 i = packet_ok(read_len, from_lsa, to, seq);
1126 /* Skip short packet */ 1137 /* Skip short packet */
1127 if (i == 0) 1138 if (icmp_code == 0)
1128 continue; 1139 continue;
1129 1140
1130 if (!gotlastaddr 1141 if (!gotlastaddr
@@ -1143,10 +1154,10 @@ common_traceroute_main(int op, char **argv)
1143 printf(" (%d)", ip->ip_ttl); 1154 printf(" (%d)", ip->ip_ttl);
1144 1155
1145 /* time exceeded in transit */ 1156 /* time exceeded in transit */
1146 if (i == -1) 1157 if (icmp_code == -1)
1147 break; 1158 break;
1148 i--; 1159 icmp_code--;
1149 switch (i) { 1160 switch (icmp_code) {
1150#if ENABLE_TRACEROUTE6 1161#if ENABLE_TRACEROUTE6
1151 case ICMP6_DST_UNREACH_NOPORT << 8: 1162 case ICMP6_DST_UNREACH_NOPORT << 8:
1152 got_there = 1; 1163 got_there = 1;
@@ -1219,16 +1230,18 @@ common_traceroute_main(int op, char **argv)
1219 ++unreachable; 1230 ++unreachable;
1220 break; 1231 break;
1221 default: 1232 default:
1222 printf(" !<%d>", i); 1233 printf(" !<%d>", icmp_code);
1223 ++unreachable; 1234 ++unreachable;
1224 break; 1235 break;
1225 } 1236 }
1226 break; 1237 break;
1227 } 1238 } /* while (wait and read a packet) */
1239
1228 /* there was no packet at all? */ 1240 /* there was no packet at all? */
1229 if (read_len == 0) 1241 if (read_len == 0)
1230 printf(" *"); 1242 printf(" *");
1231 } 1243 } /* for (nprobes) */
1244
1232 bb_putchar('\n'); 1245 bb_putchar('\n');
1233 if (got_there 1246 if (got_there
1234 || (unreachable > 0 && unreachable >= nprobes - 1) 1247 || (unreachable > 0 && unreachable >= nprobes - 1)