diff options
author | Claudius Zingerli <gitmail@zeuz.ch> | 2018-02-18 21:01:04 +0100 |
---|---|---|
committer | Sami Kerola <kerolasa@iki.fi> | 2018-10-21 14:40:30 +0100 |
commit | 918e824dc13a39e4d68fcd82fd2d248c9fba6bbd (patch) | |
tree | a02b9e73dd12c9e19d3bfaddc4286c10022c4787 | |
parent | 55e1bc80f75a1dacc6f02da24a33543402bb3f93 (diff) | |
download | iputils-918e824dc13a39e4d68fcd82fd2d248c9fba6bbd.tar.gz |
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.]
Reviewed-by: Sami Kerola <kerolasa@iki.fi>
Reference: https://github.com/iputils/iputils/pull/122
-rw-r--r-- | ping.c | 68 |
1 files changed, 48 insertions, 20 deletions
@@ -55,6 +55,7 @@ #include <netinet/ip.h> #include <netinet/ip_icmp.h> #include <ifaddrs.h> +#include <math.h> #ifndef ICMP_FILTER #define ICMP_FILTER 1 @@ -182,6 +183,40 @@ static void set_socket_option(socket_st *sock, int level, int optname, const voi error(2, errno, "setsockopt"); } +/* 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: + if (errno == ERANGE) + error(2, errno, "%s: %s", err_msg, str); + error(2, 0, "%s: %s", err_msg, str); + return num; +} + int main(int argc, char **argv) { @@ -275,27 +310,15 @@ main(int argc, char **argv) break; case 'i': { - double dbl; - char *ep; + double optval; - 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) + optval = ping_strtod(optarg, "bad timing interval"); + if (isgreater(optval, (double)(INT_MAX / 1000))) error(2, 0, "bad timing interval: %s", optarg); - - interval = (int)(dbl * 1000); - + interval = (int)(optval * 1000); options |= F_INTERVAL; - break; } + break; case 'I': /* IPv6 */ if (strchr(optarg, ':')) { @@ -411,10 +434,15 @@ main(int argc, char **argv) error(2, 0, "bad wait time: %s", optarg); break; case 'W': - lingertime = atoi(optarg); - if (lingertime <= 0 || lingertime > INT_MAX / 1000000) { + { + double optval; + + optval = ping_strtod(optarg, "bad linger time"); + if (isless(optval, 0.001) || isgreater(optval, (double)(INT_MAX / 1000))) error(2, 0, "bad linger time: %s", optarg); - lingertime *= 1000; + /* lingertime will be converted to usec later */ + lingertime = (int)(optval * 1000); + } break; default: usage(); |