Annotation of embedaddon/ntp/lib/isc/unix/time.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC")
3: * Copyright (C) 1998-2001, 2003 Internet Software Consortium.
4: *
5: * Permission to use, copy, modify, and/or distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
8: *
9: * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10: * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11: * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12: * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13: * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14: * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15: * PERFORMANCE OF THIS SOFTWARE.
16: */
17:
18: /* $Id: time.c,v 1.56 2008/02/15 23:46:51 tbox Exp $ */
19:
20: /*! \file */
21:
22: #include <config.h>
23:
24: #include <errno.h>
25: #include <limits.h>
26: #include <syslog.h>
27: #include <time.h>
28:
29: #include <sys/time.h> /* Required for struct timeval on some platforms. */
30:
31: #include <isc/log.h>
32: #include <isc/print.h>
33: #include <isc/strerror.h>
34: #include <isc/string.h>
35: #include <isc/time.h>
36: #include <isc/util.h>
37:
38: #define NS_PER_S 1000000000 /*%< Nanoseconds per second. */
39: #define NS_PER_US 1000 /*%< Nanoseconds per microsecond. */
40: #define US_PER_S 1000000 /*%< Microseconds per second. */
41:
42: /*
43: * All of the INSIST()s checks of nanoseconds < NS_PER_S are for
44: * consistency checking of the type. In lieu of magic numbers, it
45: * is the best we've got. The check is only performed on functions which
46: * need an initialized type.
47: */
48:
49: #ifndef ISC_FIX_TV_USEC
50: #define ISC_FIX_TV_USEC 1
51: #endif
52:
53: /*%
54: *** Intervals
55: ***/
56:
57: static isc_interval_t zero_interval = { 0, 0 };
58: isc_interval_t *isc_interval_zero = &zero_interval;
59:
60: #if ISC_FIX_TV_USEC
61: static inline void
62: fix_tv_usec(struct timeval *tv) {
63: isc_boolean_t fixed = ISC_FALSE;
64:
65: if (tv->tv_usec < 0) {
66: fixed = ISC_TRUE;
67: do {
68: tv->tv_sec -= 1;
69: tv->tv_usec += US_PER_S;
70: } while (tv->tv_usec < 0);
71: } else if (tv->tv_usec >= US_PER_S) {
72: fixed = ISC_TRUE;
73: do {
74: tv->tv_sec += 1;
75: tv->tv_usec -= US_PER_S;
76: } while (tv->tv_usec >=US_PER_S);
77: }
78: /*
79: * Call syslog directly as was are called from the logging functions.
80: */
81: if (fixed)
82: (void)syslog(LOG_ERR, "gettimeofday returned bad tv_usec: corrected");
83: }
84: #endif
85:
86: void
87: isc_interval_set(isc_interval_t *i,
88: unsigned int seconds, unsigned int nanoseconds)
89: {
90: REQUIRE(i != NULL);
91: REQUIRE(nanoseconds < NS_PER_S);
92:
93: i->seconds = seconds;
94: i->nanoseconds = nanoseconds;
95: }
96:
97: isc_boolean_t
98: isc_interval_iszero(const isc_interval_t *i) {
99: REQUIRE(i != NULL);
100: INSIST(i->nanoseconds < NS_PER_S);
101:
102: if (i->seconds == 0 && i->nanoseconds == 0)
103: return (ISC_TRUE);
104:
105: return (ISC_FALSE);
106: }
107:
108:
109: /***
110: *** Absolute Times
111: ***/
112:
113: static isc_time_t epoch = { 0, 0 };
114: isc_time_t *isc_time_epoch = &epoch;
115:
116: void
117: isc_time_set(isc_time_t *t, unsigned int seconds, unsigned int nanoseconds) {
118: REQUIRE(t != NULL);
119: REQUIRE(nanoseconds < NS_PER_S);
120:
121: t->seconds = seconds;
122: t->nanoseconds = nanoseconds;
123: }
124:
125: void
126: isc_time_settoepoch(isc_time_t *t) {
127: REQUIRE(t != NULL);
128:
129: t->seconds = 0;
130: t->nanoseconds = 0;
131: }
132:
133: isc_boolean_t
134: isc_time_isepoch(const isc_time_t *t) {
135: REQUIRE(t != NULL);
136: INSIST(t->nanoseconds < NS_PER_S);
137:
138: if (t->seconds == 0 && t->nanoseconds == 0)
139: return (ISC_TRUE);
140:
141: return (ISC_FALSE);
142: }
143:
144:
145: isc_result_t
146: isc_time_now(isc_time_t *t) {
147: struct timeval tv;
148: char strbuf[ISC_STRERRORSIZE];
149:
150: REQUIRE(t != NULL);
151:
152: if (gettimeofday(&tv, NULL) == -1) {
153: isc__strerror(errno, strbuf, sizeof(strbuf));
154: UNEXPECTED_ERROR(__FILE__, __LINE__, "%s", strbuf);
155: return (ISC_R_UNEXPECTED);
156: }
157:
158: /*
159: * Does POSIX guarantee the signedness of tv_sec and tv_usec? If not,
160: * then this test will generate warnings for platforms on which it is
161: * unsigned. In any event, the chances of any of these problems
162: * happening are pretty much zero, but since the libisc library ensures
163: * certain things to be true ...
164: */
165: #if ISC_FIX_TV_USEC
166: fix_tv_usec(&tv);
167: if (tv.tv_sec < 0)
168: return (ISC_R_UNEXPECTED);
169: #else
170: if (tv.tv_sec < 0 || tv.tv_usec < 0 || tv.tv_usec >= US_PER_S)
171: return (ISC_R_UNEXPECTED);
172: #endif
173:
174: /*
175: * Ensure the tv_sec value fits in t->seconds.
176: */
177: if (sizeof(tv.tv_sec) > sizeof(t->seconds) &&
178: ((tv.tv_sec | (unsigned int)-1) ^ (unsigned int)-1) != 0U)
179: return (ISC_R_RANGE);
180:
181: t->seconds = tv.tv_sec;
182: t->nanoseconds = tv.tv_usec * NS_PER_US;
183:
184: return (ISC_R_SUCCESS);
185: }
186:
187: isc_result_t
188: isc_time_nowplusinterval(isc_time_t *t, const isc_interval_t *i) {
189: struct timeval tv;
190: char strbuf[ISC_STRERRORSIZE];
191:
192: REQUIRE(t != NULL);
193: REQUIRE(i != NULL);
194: INSIST(i->nanoseconds < NS_PER_S);
195:
196: if (gettimeofday(&tv, NULL) == -1) {
197: isc__strerror(errno, strbuf, sizeof(strbuf));
198: UNEXPECTED_ERROR(__FILE__, __LINE__, "%s", strbuf);
199: return (ISC_R_UNEXPECTED);
200: }
201:
202: /*
203: * Does POSIX guarantee the signedness of tv_sec and tv_usec? If not,
204: * then this test will generate warnings for platforms on which it is
205: * unsigned. In any event, the chances of any of these problems
206: * happening are pretty much zero, but since the libisc library ensures
207: * certain things to be true ...
208: */
209: #if ISC_FIX_TV_USEC
210: fix_tv_usec(&tv);
211: if (tv.tv_sec < 0)
212: return (ISC_R_UNEXPECTED);
213: #else
214: if (tv.tv_sec < 0 || tv.tv_usec < 0 || tv.tv_usec >= US_PER_S)
215: return (ISC_R_UNEXPECTED);
216: #endif
217:
218: /*
219: * Ensure the resulting seconds value fits in the size of an
220: * unsigned int. (It is written this way as a slight optimization;
221: * note that even if both values == INT_MAX, then when added
222: * and getting another 1 added below the result is UINT_MAX.)
223: */
224: if ((tv.tv_sec > INT_MAX || i->seconds > INT_MAX) &&
225: ((long long)tv.tv_sec + i->seconds > UINT_MAX))
226: return (ISC_R_RANGE);
227:
228: t->seconds = tv.tv_sec + i->seconds;
229: t->nanoseconds = tv.tv_usec * NS_PER_US + i->nanoseconds;
230: if (t->nanoseconds >= NS_PER_S) {
231: t->seconds++;
232: t->nanoseconds -= NS_PER_S;
233: }
234:
235: return (ISC_R_SUCCESS);
236: }
237:
238: int
239: isc_time_compare(const isc_time_t *t1, const isc_time_t *t2) {
240: REQUIRE(t1 != NULL && t2 != NULL);
241: INSIST(t1->nanoseconds < NS_PER_S && t2->nanoseconds < NS_PER_S);
242:
243: if (t1->seconds < t2->seconds)
244: return (-1);
245: if (t1->seconds > t2->seconds)
246: return (1);
247: if (t1->nanoseconds < t2->nanoseconds)
248: return (-1);
249: if (t1->nanoseconds > t2->nanoseconds)
250: return (1);
251: return (0);
252: }
253:
254: isc_result_t
255: isc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result)
256: {
257: REQUIRE(t != NULL && i != NULL && result != NULL);
258: INSIST(t->nanoseconds < NS_PER_S && i->nanoseconds < NS_PER_S);
259:
260: /*
261: * Ensure the resulting seconds value fits in the size of an
262: * unsigned int. (It is written this way as a slight optimization;
263: * note that even if both values == INT_MAX, then when added
264: * and getting another 1 added below the result is UINT_MAX.)
265: */
266: if ((t->seconds > INT_MAX || i->seconds > INT_MAX) &&
267: ((long long)t->seconds + i->seconds > UINT_MAX))
268: return (ISC_R_RANGE);
269:
270: result->seconds = t->seconds + i->seconds;
271: result->nanoseconds = t->nanoseconds + i->nanoseconds;
272: if (result->nanoseconds >= NS_PER_S) {
273: result->seconds++;
274: result->nanoseconds -= NS_PER_S;
275: }
276:
277: return (ISC_R_SUCCESS);
278: }
279:
280: isc_result_t
281: isc_time_subtract(const isc_time_t *t, const isc_interval_t *i,
282: isc_time_t *result)
283: {
284: REQUIRE(t != NULL && i != NULL && result != NULL);
285: INSIST(t->nanoseconds < NS_PER_S && i->nanoseconds < NS_PER_S);
286:
287: if ((unsigned int)t->seconds < i->seconds ||
288: ((unsigned int)t->seconds == i->seconds &&
289: t->nanoseconds < i->nanoseconds))
290: return (ISC_R_RANGE);
291:
292: result->seconds = t->seconds - i->seconds;
293: if (t->nanoseconds >= i->nanoseconds)
294: result->nanoseconds = t->nanoseconds - i->nanoseconds;
295: else {
296: result->nanoseconds = NS_PER_S - i->nanoseconds +
297: t->nanoseconds;
298: result->seconds--;
299: }
300:
301: return (ISC_R_SUCCESS);
302: }
303:
304: isc_uint64_t
305: isc_time_microdiff(const isc_time_t *t1, const isc_time_t *t2) {
306: isc_uint64_t i1, i2, i3;
307:
308: REQUIRE(t1 != NULL && t2 != NULL);
309: INSIST(t1->nanoseconds < NS_PER_S && t2->nanoseconds < NS_PER_S);
310:
311: i1 = (isc_uint64_t)t1->seconds * NS_PER_S + t1->nanoseconds;
312: i2 = (isc_uint64_t)t2->seconds * NS_PER_S + t2->nanoseconds;
313:
314: if (i1 <= i2)
315: return (0);
316:
317: i3 = i1 - i2;
318:
319: /*
320: * Convert to microseconds.
321: */
322: i3 = (i1 - i2) / NS_PER_US;
323:
324: return (i3);
325: }
326:
327: isc_uint32_t
328: isc_time_seconds(const isc_time_t *t) {
329: REQUIRE(t != NULL);
330: INSIST(t->nanoseconds < NS_PER_S);
331:
332: return ((isc_uint32_t)t->seconds);
333: }
334:
335: isc_result_t
336: isc_time_secondsastimet(const isc_time_t *t, time_t *secondsp) {
337: isc_uint64_t i;
338: time_t seconds;
339:
340: REQUIRE(t != NULL);
341: INSIST(t->nanoseconds < NS_PER_S);
342:
343: /*
344: * Ensure that the number of seconds represented by t->seconds
345: * can be represented by a time_t. Since t->seconds is an unsigned
346: * int and since time_t is mostly opaque, this is trickier than
347: * it seems. (This standardized opaqueness of time_t is *very*
348: * frustrating; time_t is not even limited to being an integral
349: * type.)
350: *
351: * The mission, then, is to avoid generating any kind of warning
352: * about "signed versus unsigned" while trying to determine if the
353: * the unsigned int t->seconds is out range for tv_sec, which is
354: * pretty much only true if time_t is a signed integer of the same
355: * size as the return value of isc_time_seconds.
356: *
357: * The use of the 64 bit integer ``i'' takes advantage of C's
358: * conversion rules to either zero fill or sign extend the widened
359: * type.
360: *
361: * Solaris 5.6 gives this warning about the left shift:
362: * warning: integer overflow detected: op "<<"
363: * if the U(nsigned) qualifier is not on the 1.
364: */
365: seconds = (time_t)t->seconds;
366:
367: INSIST(sizeof(unsigned int) == sizeof(isc_uint32_t));
368: INSIST(sizeof(time_t) >= sizeof(isc_uint32_t));
369:
370: if (sizeof(time_t) == sizeof(isc_uint32_t) && /* Same size. */
371: (time_t)0.5 != 0.5 && /* Not a floating point type. */
372: (i = (time_t)-1) != 4294967295u && /* Is signed. */
373: (seconds &
374: (1U << (sizeof(time_t) * CHAR_BIT - 1))) != 0U) { /* Negative. */
375: /*
376: * This UNUSED() is here to shut up the IRIX compiler:
377: * variable "i" was set but never used
378: * when the value of i *was* used in the third test.
379: * (Let's hope the compiler got the actual test right.)
380: */
381: UNUSED(i);
382: return (ISC_R_RANGE);
383: }
384:
385: *secondsp = seconds;
386:
387: return (ISC_R_SUCCESS);
388: }
389:
390: isc_uint32_t
391: isc_time_nanoseconds(const isc_time_t *t) {
392: REQUIRE(t != NULL);
393:
394: ENSURE(t->nanoseconds < NS_PER_S);
395:
396: return ((isc_uint32_t)t->nanoseconds);
397: }
398:
399: void
400: isc_time_formattimestamp(const isc_time_t *t, char *buf, unsigned int len) {
401: time_t now;
402: unsigned int flen;
403:
404: REQUIRE(len > 0);
405:
406: now = (time_t) t->seconds;
407: flen = strftime(buf, len, "%d-%b-%Y %X", localtime(&now));
408: INSIST(flen < len);
409: if (flen != 0)
410: snprintf(buf + flen, len - flen,
411: ".%03u", t->nanoseconds / 1000000);
412: else
413: snprintf(buf, len, "99-Bad-9999 99:99:99.999");
414: }
415:
416: void
417: isc_time_formathttptimestamp(const isc_time_t *t, char *buf, unsigned int len) {
418: time_t now;
419: unsigned int flen;
420:
421: REQUIRE(len > 0);
422:
423: now = (time_t)t->seconds;
424: flen = strftime(buf, len, "%a, %d %b %Y %H:%M:%S GMT", gmtime(&now));
425: INSIST(flen < len);
426: }
427:
428: void
429: isc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len) {
430: time_t now;
431: unsigned int flen;
432:
433: REQUIRE(len > 0);
434:
435: now = (time_t)t->seconds;
436: flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%SZ", gmtime(&now));
437: INSIST(flen < len);
438: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>