From c78e3129d404f20d556f727ceee3704722de8cc7 Mon Sep 17 00:00:00 2001 From: Vladislav Grishenko Date: Wed, 15 Aug 2018 22:03:45 +0500 Subject: [PATCH] pppd: linux: use monotonic time if possible gettimeofday() suffers from time jumps due ntp or any manual change, so duration measurements and scheduling can not be accurate. let's use monotonic time source instead, if available. it's known glibc (< 2.3.4) & old uclibc don't provide CLOCK_MONOTONIC denine, but kernel may have it supported. so, use clock_gettime() with fallback to gettimeofday() if first call has failed. several gettimeofday()/time() calls still have to be preserved for debug, pseudoterminal timestamping and string formatting. all the rest calls are replaced to new get_time() call. solaris kept with gettimeofday() as before, corresponding get_time() system implementation can be updated/added in any future. Signed-off-by: Vladislav Grishenko --- pppd/Makefile.linux | 2 +- pppd/main.c | 12 +++++------ pppd/plugins/radius/buildreq.c | 13 ++++++------ pppd/plugins/rp-pppoe/discovery.c | 12 +++++------ pppd/pppd.h | 2 ++ pppd/sys-linux.c | 35 +++++++++++++++++++++++++++++++ pppd/sys-solaris.c | 11 ++++++++++ pppd/tty.c | 4 ++-- 8 files changed, 70 insertions(+), 21 deletions(-) diff --git a/pppd/Makefile.linux b/pppd/Makefile.linux index 8d5ce99..2a05bc4 100644 --- a/pppd/Makefile.linux +++ b/pppd/Makefile.linux @@ -33,7 +33,7 @@ endif # CC = gcc # COPTS = -O2 -pipe -Wall -g -LIBS = +LIBS = -lrt # Uncomment the next line to include support for Microsoft's # MS-CHAP authentication protocol. Also, edit plugins/radius/Makefile.linux. diff --git a/pppd/main.c b/pppd/main.c index e09b6ff..dccd78b 100644 --- a/pppd/main.c +++ b/pppd/main.c @@ -522,7 +522,7 @@ main(argc, argv) info("Starting link"); } - gettimeofday(&start_time, NULL); + get_time(&start_time); script_unsetenv("CONNECT_TIME"); script_unsetenv("BYTES_SENT"); script_unsetenv("BYTES_RCVD"); @@ -1216,7 +1216,7 @@ reset_link_stats(u) { if (!get_ppp_stats(u, &old_link_stats)) return; - gettimeofday(&start_time, NULL); + get_time(&start_time); } /* @@ -1230,7 +1230,7 @@ update_link_stats(u) char numbuf[32]; if (!get_ppp_stats(u, &link_stats) - || gettimeofday(&now, NULL) < 0) + || get_time(&now) < 0) return; link_connect_time = now.tv_sec - start_time.tv_sec; link_stats_valid = 1; @@ -1277,7 +1277,7 @@ timeout(func, arg, secs, usecs) fatal("Out of memory in timeout()!"); newp->c_arg = arg; newp->c_func = func; - gettimeofday(&timenow, NULL); + get_time(&timenow); newp->c_time.tv_sec = timenow.tv_sec + secs; newp->c_time.tv_usec = timenow.tv_usec + usecs; if (newp->c_time.tv_usec >= 1000000) { @@ -1331,7 +1331,7 @@ calltimeout() while (callout != NULL) { p = callout; - if (gettimeofday(&timenow, NULL) < 0) + if (get_time(&timenow) < 0) fatal("Failed to get time of day: %m"); if (!(p->c_time.tv_sec < timenow.tv_sec || (p->c_time.tv_sec == timenow.tv_sec @@ -1356,7 +1356,7 @@ timeleft(tvp) if (callout == NULL) return NULL; - gettimeofday(&timenow, NULL); + get_time(&timenow); tvp->tv_sec = callout->c_time.tv_sec - timenow.tv_sec; tvp->tv_usec = callout->c_time.tv_usec - timenow.tv_usec; if (tvp->tv_usec < 0) { diff --git a/pppd/plugins/radius/buildreq.c b/pppd/plugins/radius/buildreq.c index 955b052..3edd5ea 100644 --- a/pppd/plugins/radius/buildreq.c +++ b/pppd/plugins/radius/buildreq.c @@ -293,7 +293,7 @@ int rc_acct_using_server(SERVER *acctserver, SEND_DATA data; VALUE_PAIR *adt_vp; int result; - time_t start_time, dtime; + struct timeval start_time, dtime; char msg[4096]; int i; int timeout = rc_conf_int("radius_timeout"); @@ -320,11 +320,11 @@ int rc_acct_using_server(SERVER *acctserver, * Fill in Acct-Delay-Time */ - dtime = 0; - if ((adt_vp = rc_avpair_add(&(data.send_pairs), PW_ACCT_DELAY_TIME, &dtime, 0, VENDOR_NONE)) == NULL) + dtime.tv_sec = 0; + if ((adt_vp = rc_avpair_add(&(data.send_pairs), PW_ACCT_DELAY_TIME, &dtime.tv_sec, 0, VENDOR_NONE)) == NULL) return (ERROR_RC); - start_time = time(NULL); + get_time(&start_time); result = ERROR_RC; for(i=0; (imax) && (result != OK_RC) && (result != BADRESP_RC) ; i++) @@ -336,8 +336,9 @@ int rc_acct_using_server(SERVER *acctserver, rc_buildreq(&data, PW_ACCOUNTING_REQUEST, acctserver->name[i], acctserver->port[i], timeout, retries); - dtime = time(NULL) - start_time; - rc_avpair_assign(adt_vp, &dtime, 0); + get_time(&dtime); + dtime.tv_sec -= start_time.tv_sec; + rc_avpair_assign(adt_vp, &dtime.tv_sec, 0); result = rc_send_server (&data, msg, NULL); } diff --git a/pppd/plugins/rp-pppoe/discovery.c b/pppd/plugins/rp-pppoe/discovery.c index 2aebcd1..a4e4cec 100644 --- a/pppd/plugins/rp-pppoe/discovery.c +++ b/pppd/plugins/rp-pppoe/discovery.c @@ -45,8 +45,8 @@ static int time_left(struct timeval *diff, struct timeval *exp) { struct timeval now; - if (gettimeofday(&now, NULL) < 0) { - error("gettimeofday: %m"); + if (get_time(&now) < 0) { + error("get_time: %m"); return 0; } @@ -353,8 +353,8 @@ waitForPADO(PPPoEConnection *conn, int timeout) conn->seenMaxPayload = 0; conn->error = 0; - if (gettimeofday(&expire_at, NULL) < 0) { - error("gettimeofday (waitForPADO): %m"); + if (get_time(&expire_at) < 0) { + error("get_time (waitForPADO): %m"); return; } expire_at.tv_sec += timeout; @@ -533,8 +533,8 @@ waitForPADS(PPPoEConnection *conn, int timeout) PPPoEPacket packet; int len; - if (gettimeofday(&expire_at, NULL) < 0) { - error("gettimeofday (waitForPADS): %m"); + if (get_time(&expire_at) < 0) { + error("get_time (waitForPADS): %m"); return; } expire_at.tv_sec += timeout; diff --git a/pppd/pppd.h b/pppd/pppd.h index 6e3743f..9214aae 100644 --- a/pppd/pppd.h +++ b/pppd/pppd.h @@ -705,6 +705,8 @@ int cipxfaddr __P((int)); #endif int get_if_hwaddr __P((u_char *addr, char *name)); char *get_first_ethernet __P((void)); +int get_time __P((struct timeval *)); + /* Get current time, monotonic if possible. */ /* Procedures exported from options.c */ int setipaddr __P((char *, char **, int)); /* Set local/remote ip addresses */ diff --git a/pppd/sys-linux.c b/pppd/sys-linux.c index 761aafc..b395991 100644 --- a/pppd/sys-linux.c +++ b/pppd/sys-linux.c @@ -2966,3 +2966,38 @@ ether_to_eui64(eui64_t *p_eui64) return 1; } #endif + +/******************************************************************** + * + * get_time - Get current time, monotonic if possible. + */ +int +get_time(struct timeval *tv) +{ +/* Old glibc (< 2.3.4) does define CLOCK_MONOTONIC, but kernel may have it. + * Runtime checking makes it safe. */ +#ifndef CLOCK_MONOTONIC +#define CLOCK_MONOTONIC 1 +#endif + static int monotonic = -1; + struct timespec ts; + int ret; + + if (monotonic) { + ret = clock_gettime(CLOCK_MONOTONIC, &ts); + if (ret == 0) { + monotonic = 1; + if (tv) { + tv->tv_sec = ts.tv_sec; + tv->tv_usec = ts.tv_nsec / 1000; + } + return ret; + } else if (monotonic > 0) + return ret; + + monotonic = 0; + warn("Couldn't use monotonic clock source: %m"); + } + + return gettimeofday(tv, NULL); +} diff --git a/pppd/sys-solaris.c b/pppd/sys-solaris.c index 93d9033..83b1815 100644 --- a/pppd/sys-solaris.c +++ b/pppd/sys-solaris.c @@ -114,6 +114,7 @@ #include #include #include +#include #include #include #include @@ -2783,3 +2784,13 @@ get_pty(master_fdp, slave_fdp, slave_name, uid) return 1; } + +/******************************************************************** + * + * get_time - Get current time, monotonic if possible. + */ +int +get_time(struct timeval *tv) +{ + return gettimeofday(tv, NULL); +} diff --git a/pppd/tty.c b/pppd/tty.c index c9a0b33..485a44d 100644 --- a/pppd/tty.c +++ b/pppd/tty.c @@ -1072,7 +1072,7 @@ charshunt(ifd, ofd, record_file) pty_readable = stdin_readable = 1; ilevel = olevel = 0; - gettimeofday(&levelt, NULL); + get_time(&levelt); if (max_data_rate) { max_level = max_data_rate / 10; if (max_level < 100) @@ -1121,7 +1121,7 @@ charshunt(ifd, ofd, record_file) int nbt; struct timeval now; - gettimeofday(&now, NULL); + get_time(&now); dt = (now.tv_sec - levelt.tv_sec + (now.tv_usec - levelt.tv_usec) / 1e6); nbt = (int)(dt * max_data_rate); -- 2.39.2