147 lines
4.0 KiB
Diff
147 lines
4.0 KiB
Diff
From 9633d828e8166e47af733cbc6563ac93e5e06a30 Mon Sep 17 00:00:00 2001
|
|
From: Jan Macku <jamacku@redhat.com>
|
|
Date: Wed, 9 Dec 2020 10:23:09 +0100
|
|
Subject: [PATCH] ping: add support for sub-second timeouts
|
|
|
|
Timeouts (-W) were previously silently rounded down to the next lower
|
|
integral number. Subsecond values were rounded to zero which resulted in
|
|
infinite timeouts, therefore ping never exited if there were no responses
|
|
and timeouts below 1s. This commit fixes this issue.
|
|
|
|
[Sami: I changed ping_strtod() to return double. Claudius did updated
|
|
needed value by pointer reference, and had multiplication by 1000 in
|
|
wrapper function. I think that made understanding the code unnecessarily
|
|
difficult, so implementation was slightly changed.]
|
|
|
|
Backported from upstream PATCH:
|
|
918e824dc13a39e4d68fcd82fd2d248c9fba6bbd Claudius Zingerli <gitmail@zeuz.ch>
|
|
93dfb95d48977d151dbe94983e4998959e748aee Rosen Penev <rosenp@gmail.com>
|
|
---
|
|
ping.c | 89 ++++++++++++++++++++++++++++++++++++++--------------------
|
|
1 file changed, 58 insertions(+), 31 deletions(-)
|
|
|
|
diff --git a/ping.c b/ping.c
|
|
index d9a3f5d..33f7d45 100644
|
|
--- a/ping.c
|
|
+++ b/ping.c
|
|
@@ -57,6 +57,7 @@
|
|
#ifndef WITHOUT_IFADDRS
|
|
#include <ifaddrs.h>
|
|
#endif
|
|
+#include <math.h>
|
|
|
|
#ifndef ICMP_FILTER
|
|
#define ICMP_FILTER 1
|
|
@@ -192,6 +193,38 @@ static void set_socket_option(socket_st *sock, int level, int optname, const voi
|
|
}
|
|
}
|
|
|
|
+/* Much like stdtod(3, but will fails if str is not valid number. */
|
|
+static double ping_strtod(const char *str, const char *err_msg)
|
|
+{
|
|
+ double num;
|
|
+ char *end = NULL;
|
|
+
|
|
+ if (str == NULL || *str == '\0')
|
|
+ goto err;
|
|
+ errno = 0;
|
|
+#ifdef USE_IDN
|
|
+ setlocale(LC_ALL, "C");
|
|
+#endif
|
|
+ num = strtod(str, &end);
|
|
+#ifdef USE_IDN
|
|
+ setlocale(LC_ALL, "");
|
|
+#endif
|
|
+ if (errno || str == end || (end && *end))
|
|
+ goto err;
|
|
+ switch (fpclassify(num)) {
|
|
+ case FP_NORMAL:
|
|
+ case FP_ZERO:
|
|
+ break;
|
|
+ default:
|
|
+ errno = ERANGE;
|
|
+ goto err;
|
|
+ }
|
|
+ return num;
|
|
+err:
|
|
+ fprintf(stderr, "%s: %s", err_msg, str);
|
|
+ exit(2);
|
|
+}
|
|
+
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
@@ -298,30 +331,19 @@ main(int argc, char **argv)
|
|
options |= F_PTIMEOFDAY;
|
|
break;
|
|
case 'i':
|
|
- {
|
|
- double dbl;
|
|
- char *ep;
|
|
-
|
|
- errno = 0;
|
|
-#ifdef USE_IDN
|
|
- setlocale(LC_ALL, "C");
|
|
-#endif
|
|
- dbl = strtod(optarg, &ep);
|
|
-#ifdef USE_IDN
|
|
- setlocale(LC_ALL, "");
|
|
-#endif
|
|
-
|
|
- if (errno || *ep != '\0' ||
|
|
- !finite(dbl) || dbl < 0.0 || dbl >= (double)INT_MAX / 1000 - 1.0) {
|
|
- fprintf(stderr, "ping: bad timing interval\n");
|
|
- exit(2);
|
|
- }
|
|
-
|
|
- interval = (int)(dbl * 1000);
|
|
-
|
|
- options |= F_INTERVAL;
|
|
- break;
|
|
- }
|
|
+ {
|
|
+ double optval;
|
|
+
|
|
+ optval = ping_strtod(optarg, "bad timing interval");
|
|
+ if (isgreater(optval, (double)INT_MAX / 1000)) {
|
|
+ fprintf(stderr, "ping: bad timing interval\n");
|
|
+ exit(2);
|
|
+ }
|
|
+
|
|
+ interval = (int)(optval * 1000);
|
|
+ options |= F_INTERVAL;
|
|
+ }
|
|
+ break;
|
|
case 'I':
|
|
/* IPv6 */
|
|
if (strchr(optarg, ':')) {
|
|
@@ -460,13 +482,18 @@ main(int argc, char **argv)
|
|
}
|
|
break;
|
|
case 'W':
|
|
- lingertime = atoi(optarg);
|
|
- if (lingertime < 0 || lingertime > INT_MAX/1000000) {
|
|
- fprintf(stderr, "ping: bad linger time.\n");
|
|
- exit(2);
|
|
- }
|
|
- lingertime *= 1000;
|
|
- break;
|
|
+ {
|
|
+ double optval;
|
|
+
|
|
+ optval = ping_strtod(optarg, "bad linger time");
|
|
+ if (isless(optval, 0.001) || isgreater(optval, (double)INT_MAX / 1000)) {
|
|
+ fprintf(stderr, "ping: bad linger time.\n");
|
|
+ exit(2);
|
|
+ }
|
|
+ /* lingertime will be converted to usec later */
|
|
+ lingertime = (int)(optval * 1000);
|
|
+ }
|
|
+ break;
|
|
default:
|
|
usage();
|
|
break;
|
|
--
|
|
2.29.2
|
|
|