From 44c6352e5710e98929e915f5526050a396e61275 Mon Sep 17 00:00:00 2001 From: Ken Raeburn Date: Tue, 15 Jun 2004 19:06:13 +0000 Subject: [PATCH] Localize the OS-specific bits of retrieving the current time a bit more. ** not yet tested on Windows ** * c_ustime.c: Include k5-thread.h. (get_time_now): New function, holds system-dependent code. (krb5int_us_time_mutex): New mutex. (struct time_now): New type. (last_time): New variable, replaces old last_tv, last_sec, last_usec. (krb5_crypto_us_timeofday): Rewrite. Do locking around access to previously returned value, and ensure that we don't return duplicate values. * os-proto.h: Include k5-thread.h. (krb5int_us_time_mutex): Declare. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@16454 dc483132-0cff-0310-8789-dd5450dbe970 --- src/lib/krb5/os/ChangeLog | 14 +++++ src/lib/krb5/os/c_ustime.c | 105 +++++++++++++++++++++---------------- src/lib/krb5/os/os-proto.h | 3 ++ 3 files changed, 78 insertions(+), 44 deletions(-) diff --git a/src/lib/krb5/os/ChangeLog b/src/lib/krb5/os/ChangeLog index 07ab6ee09..606b1a44f 100644 --- a/src/lib/krb5/os/ChangeLog +++ b/src/lib/krb5/os/ChangeLog @@ -1,3 +1,17 @@ +2004-06-15 Ken Raeburn + + * c_ustime.c: Include k5-thread.h. + (get_time_now): New function, holds system-dependent code. + (krb5int_us_time_mutex): New mutex. + (struct time_now): New type. + (last_time): New variable, replaces old last_tv, last_sec, + last_usec. + (krb5_crypto_us_timeofday): Rewrite. Do locking around access to + previously returned value, and ensure that we don't return + duplicate values. + * os-proto.h: Include k5-thread.h. + (krb5int_us_time_mutex): Declare. + 2004-06-04 Ken Raeburn * kuserok.c (krb5_kuserok): Handle draft POSIX versions of diff --git a/src/lib/krb5/os/c_ustime.c b/src/lib/krb5/os/c_ustime.c index 4a049649f..81998daab 100644 --- a/src/lib/krb5/os/c_ustime.c +++ b/src/lib/krb5/os/c_ustime.c @@ -29,6 +29,11 @@ #define NEED_SOCKETS #include "k5-int.h" +#include "k5-thread.h" + +k5_mutex_t krb5int_us_time_mutex = K5_MUTEX_PARTIAL_INITIALIZER; + +struct time_now { krb5_int32 sec, usec; }; #if defined(_WIN32) @@ -39,63 +44,75 @@ #include #include -krb5_error_code -krb5_crypto_us_timeofday(seconds, microseconds) -register krb5_int32 *seconds, *microseconds; +static krb5_error_code +get_time_now(struct time_now *n) { struct _timeb timeptr; - krb5_int32 sec, usec; - static krb5_int32 last_sec = 0; - static krb5_int32 last_usec = 0; - - _ftime(&timeptr); /* Get the current time */ - sec = timeptr.time; - usec = timeptr.millitm * 1000; - - if ((sec == last_sec) && (usec <= last_usec)) { /* Same as last time??? */ - usec = ++last_usec; - if (usec >= 1000000) { - ++sec; - usec = 0; - } - } - last_sec = sec; /* Remember for next time */ - last_usec = usec; - - *seconds = sec; /* Return the values */ - *microseconds = usec; - + _ftime(&timeptr); + n->sec = timeptr.time; + n->usec = timeptr.millitm * 1000; return 0; } #else +/* Everybody else is UNIX, right? POSIX 1996 doesn't give us + gettimeofday, but what real OS doesn't? */ + +static krb5_error_code +get_time_now(struct time_now *n) +{ + struct timeval tv; + + if (gettimeofday(&tv, (struct timezone *)0) == -1) + return errno; -/* We're a Unix machine -- do Unix time things. */ + n->sec = tv.tv_sec; + n->usec = tv.tv_usec; + return 0; +} -static struct timeval last_tv = {0, 0}; +#endif + +static struct time_now last_time; krb5_error_code -krb5_crypto_us_timeofday(register krb5_int32 *seconds, register krb5_int32 *microseconds) +krb5_crypto_us_timeofday(krb5_int32 *seconds, krb5_int32 *microseconds) { - struct timeval tv; + struct time_now now; + krb5_error_code err; - if (gettimeofday(&tv, (struct timezone *)0) == -1) { - /* failed, return errno */ - return (krb5_error_code) errno; + err = get_time_now(&now); + if (err) + return err; + + err = k5_mutex_lock(&krb5int_us_time_mutex); + if (err) + return err; + /* Just guessing: If the number of seconds hasn't changed, yet the + microseconds are moving backwards, we probably just got a third + instance of returning the same clock value from the system, so + the saved value was artificially incremented. + + On Windows, where we get millisecond accuracy currently, that's + quite likely. On UNIX, it appears that we always get new + microsecond values, so this case should never trigger. */ + if ((now.sec == last_time.sec) && (now.usec <= last_time.usec)) { + /* Same as last time??? */ + now.usec = ++last_time.usec; + if (now.usec >= 1000000) { + ++now.sec; + now.usec = 0; + } + /* For now, we're not worrying about the case of enough + returns of the same value that we roll over now.sec, and + the next call still gets the previous now.sec value. */ } - if ((tv.tv_sec == last_tv.tv_sec) && (tv.tv_usec == last_tv.tv_usec)) { - if (++last_tv.tv_usec >= 1000000) { - last_tv.tv_usec = 0; - last_tv.tv_sec++; - } - tv = last_tv; - } else - last_tv = tv; - - *seconds = tv.tv_sec; - *microseconds = tv.tv_usec; + last_time.sec = now.sec; /* Remember for next time */ + last_time.usec = now.usec; + k5_mutex_unlock(&krb5int_us_time_mutex); + + *seconds = now.sec; + *microseconds = now.usec; return 0; } - -#endif diff --git a/src/lib/krb5/os/os-proto.h b/src/lib/krb5/os/os-proto.h index bc26a1dd9..2e270d5c5 100644 --- a/src/lib/krb5/os/os-proto.h +++ b/src/lib/krb5/os/os-proto.h @@ -60,6 +60,9 @@ int _krb5_use_dns_realm (krb5_context); int _krb5_use_dns_kdc (krb5_context); int _krb5_conf_boolean (const char *); +#include "k5-thread.h" +extern k5_mutex_t krb5int_us_time_mutex; + extern unsigned int krb5_max_skdc_timeout; extern unsigned int krb5_skdc_timeout_shift; extern unsigned int krb5_skdc_timeout_1; -- 2.26.2