1 /* 2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 #pragma ident "%Z%%M% %I% %E% SMI" 7 8 /* 9 * lib/crypto/os/c_ustime.c 10 * 11 * Copyright 1990,1991 by the Massachusetts Institute of Technology. 12 * All Rights Reserved. 13 * 14 * Export of this software from the United States of America may 15 * require a specific license from the United States Government. 16 * It is the responsibility of any person or organization contemplating 17 * export to obtain such a license before exporting. 18 * 19 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 20 * distribute this software and its documentation for any purpose and 21 * without fee is hereby granted, provided that the above copyright 22 * notice appear in all copies and that both that copyright notice and 23 * this permission notice appear in supporting documentation, and that 24 * the name of M.I.T. not be used in advertising or publicity pertaining 25 * to distribution of the software without specific, written prior 26 * permission. Furthermore if you modify this software you must label 27 * your software as modified software and not distribute it in such a 28 * fashion that it might be confused with the original M.I.T. software. 29 * M.I.T. makes no representations about the suitability of 30 * this software for any purpose. It is provided "as is" without express 31 * or implied warranty. 32 * 33 * 34 * krb5_mstimeofday for BSD 4.3 35 */ 36 37 38 #define NEED_SOCKETS 39 #include "k5-int.h" 40 #include "k5-thread.h" 41 42 43 k5_mutex_t krb5int_us_time_mutex = K5_MUTEX_PARTIAL_INITIALIZER; 44 45 struct time_now { krb5_int32 sec, usec; }; 46 47 #if defined(_WIN32) 48 49 /* Microsoft Windows NT and 95 (32bit) */ 50 /* This one works for WOW (Windows on Windows, ntvdm on Win-NT) */ 51 52 #include <time.h> 53 #include <sys/timeb.h> 54 #include <string.h> 55 56 static krb5_error_code 57 get_time_now(struct time_now *n) 58 { 59 struct _timeb timeptr; 60 _ftime(&timeptr); 61 n->sec = timeptr.time; 62 n->usec = timeptr.millitm * 1000; 63 return 0; 64 } 65 66 #else 67 68 69 /* Everybody else is UNIX, right? POSIX 1996 doesn't give us 70 gettimeofday, but what real OS doesn't? */ 71 72 static krb5_error_code 73 get_time_now(struct time_now *n) 74 { 75 struct timeval tv; 76 #ifdef _KERNEL 77 timestruc_t now; 78 79 gethrestime(&now); 80 tv.tv_sec = now.tv_sec; 81 tv.tv_usec = now.tv_nsec / (NANOSEC / MICROSEC); 82 #else 83 if (gettimeofday(&tv, (struct timezone *)0) == -1) 84 return errno; 85 #endif 86 87 n->sec = tv.tv_sec; 88 n->usec = tv.tv_usec; 89 return 0; 90 } 91 #endif 92 93 static struct time_now last_time; 94 95 krb5_error_code 96 krb5_crypto_us_timeofday(krb5_int32 *seconds, krb5_int32 *microseconds) 97 { 98 struct time_now now; 99 krb5_error_code err; 100 101 err = get_time_now(&now); 102 if (err) 103 return err; 104 105 err = k5_mutex_lock(&krb5int_us_time_mutex); 106 if (err) 107 return err; 108 /* Just guessing: If the number of seconds hasn't changed, yet the 109 microseconds are moving backwards, we probably just got a third 110 instance of returning the same clock value from the system, so 111 the saved value was artificially incremented. 112 113 On Windows, where we get millisecond accuracy currently, that's 114 quite likely. On UNIX, it appears that we always get new 115 microsecond values, so this case should never trigger. */ 116 if ((now.sec == last_time.sec) && (now.usec <= last_time.usec)) { 117 /* Same as last time??? */ 118 now.usec = ++last_time.usec; 119 if (now.usec >= 1000000) { 120 ++now.sec; 121 now.usec = 0; 122 } 123 /* For now, we're not worrying about the case of enough 124 returns of the same value that we roll over now.sec, and 125 the next call still gets the previous now.sec value. */ 126 } 127 last_time.sec = now.sec; /* Remember for next time */ 128 last_time.usec = now.usec; 129 (void) k5_mutex_unlock(&krb5int_us_time_mutex); 130 131 *seconds = now.sec; 132 *microseconds = now.usec; 133 return 0; 134 } 135