xref: /illumos-gate/usr/src/uts/common/gssapi/mechs/krb5/krb5/os/c_ustime.c (revision 505d05c73a6e56769f263d4803b22eddd168ee24)
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