/src/ntp-dev/lib/isc/unix/time.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) 2004-2008, 2011, 2012 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$ */ |
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 | 0 | #define NS_PER_S 1000000000 /*%< Nanoseconds per second. */ |
39 | 0 | #define NS_PER_US 1000 /*%< Nanoseconds per microsecond. */ |
40 | 0 | #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 | 0 | fix_tv_usec(struct timeval *tv) { |
63 | 0 | isc_boolean_t fixed = ISC_FALSE; |
64 | |
|
65 | 0 | if (tv->tv_usec < 0) { |
66 | 0 | fixed = ISC_TRUE; |
67 | 0 | do { |
68 | 0 | tv->tv_sec -= 1; |
69 | 0 | tv->tv_usec += US_PER_S; |
70 | 0 | } while (tv->tv_usec < 0); |
71 | 0 | } else if (tv->tv_usec >= US_PER_S) { |
72 | 0 | fixed = ISC_TRUE; |
73 | 0 | do { |
74 | 0 | tv->tv_sec += 1; |
75 | 0 | tv->tv_usec -= US_PER_S; |
76 | 0 | } while (tv->tv_usec >=US_PER_S); |
77 | 0 | } |
78 | | /* |
79 | | * Call syslog directly as was are called from the logging functions. |
80 | | */ |
81 | 0 | if (fixed) |
82 | 0 | (void)syslog(LOG_ERR, "gettimeofday returned bad tv_usec: corrected"); |
83 | 0 | } |
84 | | #endif |
85 | | |
86 | | void |
87 | | isc_interval_set(isc_interval_t *i, |
88 | | unsigned int seconds, unsigned int nanoseconds) |
89 | 0 | { |
90 | 0 | REQUIRE(i != NULL); |
91 | 0 | REQUIRE(nanoseconds < NS_PER_S); |
92 | | |
93 | 0 | i->seconds = seconds; |
94 | 0 | i->nanoseconds = nanoseconds; |
95 | 0 | } |
96 | | |
97 | | isc_boolean_t |
98 | 0 | isc_interval_iszero(const isc_interval_t *i) { |
99 | 0 | REQUIRE(i != NULL); |
100 | 0 | INSIST(i->nanoseconds < NS_PER_S); |
101 | | |
102 | 0 | if (i->seconds == 0 && i->nanoseconds == 0) |
103 | 0 | return (ISC_TRUE); |
104 | | |
105 | 0 | return (ISC_FALSE); |
106 | 0 | } |
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 | 0 | isc_time_set(isc_time_t *t, unsigned int seconds, unsigned int nanoseconds) { |
118 | 0 | REQUIRE(t != NULL); |
119 | 0 | REQUIRE(nanoseconds < NS_PER_S); |
120 | | |
121 | 0 | t->seconds = seconds; |
122 | 0 | t->nanoseconds = nanoseconds; |
123 | 0 | } |
124 | | |
125 | | void |
126 | 0 | isc_time_settoepoch(isc_time_t *t) { |
127 | 0 | REQUIRE(t != NULL); |
128 | | |
129 | 0 | t->seconds = 0; |
130 | 0 | t->nanoseconds = 0; |
131 | 0 | } |
132 | | |
133 | | isc_boolean_t |
134 | 0 | isc_time_isepoch(const isc_time_t *t) { |
135 | 0 | REQUIRE(t != NULL); |
136 | 0 | INSIST(t->nanoseconds < NS_PER_S); |
137 | | |
138 | 0 | if (t->seconds == 0 && t->nanoseconds == 0) |
139 | 0 | return (ISC_TRUE); |
140 | | |
141 | 0 | return (ISC_FALSE); |
142 | 0 | } |
143 | | |
144 | | |
145 | | isc_result_t |
146 | 0 | isc_time_now(isc_time_t *t) { |
147 | 0 | struct timeval tv; |
148 | 0 | char strbuf[ISC_STRERRORSIZE]; |
149 | |
|
150 | 0 | REQUIRE(t != NULL); |
151 | | |
152 | 0 | if (gettimeofday(&tv, NULL) == -1) { |
153 | 0 | isc__strerror(errno, strbuf, sizeof(strbuf)); |
154 | 0 | UNEXPECTED_ERROR(__FILE__, __LINE__, "%s", strbuf); |
155 | 0 | return (ISC_R_UNEXPECTED); |
156 | 0 | } |
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 | 0 | #if ISC_FIX_TV_USEC |
166 | 0 | fix_tv_usec(&tv); |
167 | 0 | if (tv.tv_sec < 0) |
168 | 0 | 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 | 0 | if (sizeof(tv.tv_sec) > sizeof(t->seconds) && |
178 | 0 | ((tv.tv_sec | (unsigned int)-1) ^ (unsigned int)-1) != 0U) |
179 | 0 | return (ISC_R_RANGE); |
180 | | |
181 | 0 | t->seconds = tv.tv_sec; |
182 | 0 | t->nanoseconds = tv.tv_usec * NS_PER_US; |
183 | |
|
184 | 0 | return (ISC_R_SUCCESS); |
185 | 0 | } |
186 | | |
187 | | isc_result_t |
188 | 0 | isc_time_nowplusinterval(isc_time_t *t, const isc_interval_t *i) { |
189 | 0 | struct timeval tv; |
190 | 0 | char strbuf[ISC_STRERRORSIZE]; |
191 | |
|
192 | 0 | REQUIRE(t != NULL); |
193 | 0 | REQUIRE(i != NULL); |
194 | 0 | INSIST(i->nanoseconds < NS_PER_S); |
195 | | |
196 | 0 | if (gettimeofday(&tv, NULL) == -1) { |
197 | 0 | isc__strerror(errno, strbuf, sizeof(strbuf)); |
198 | 0 | UNEXPECTED_ERROR(__FILE__, __LINE__, "%s", strbuf); |
199 | 0 | return (ISC_R_UNEXPECTED); |
200 | 0 | } |
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 | 0 | #if ISC_FIX_TV_USEC |
210 | 0 | fix_tv_usec(&tv); |
211 | 0 | if (tv.tv_sec < 0) |
212 | 0 | 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 | 0 | if ((tv.tv_sec > INT_MAX || i->seconds > INT_MAX) && |
225 | 0 | ((long long)tv.tv_sec + i->seconds > UINT_MAX)) |
226 | 0 | return (ISC_R_RANGE); |
227 | | |
228 | 0 | t->seconds = tv.tv_sec + i->seconds; |
229 | 0 | t->nanoseconds = tv.tv_usec * NS_PER_US + i->nanoseconds; |
230 | 0 | if (t->nanoseconds >= NS_PER_S) { |
231 | 0 | t->seconds++; |
232 | 0 | t->nanoseconds -= NS_PER_S; |
233 | 0 | } |
234 | |
|
235 | 0 | return (ISC_R_SUCCESS); |
236 | 0 | } |
237 | | |
238 | | int |
239 | 0 | isc_time_compare(const isc_time_t *t1, const isc_time_t *t2) { |
240 | 0 | REQUIRE(t1 != NULL && t2 != NULL); |
241 | 0 | INSIST(t1->nanoseconds < NS_PER_S && t2->nanoseconds < NS_PER_S); |
242 | | |
243 | 0 | if (t1->seconds < t2->seconds) |
244 | 0 | return (-1); |
245 | 0 | if (t1->seconds > t2->seconds) |
246 | 0 | return (1); |
247 | 0 | if (t1->nanoseconds < t2->nanoseconds) |
248 | 0 | return (-1); |
249 | 0 | if (t1->nanoseconds > t2->nanoseconds) |
250 | 0 | return (1); |
251 | 0 | return (0); |
252 | 0 | } |
253 | | |
254 | | isc_result_t |
255 | | isc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result) |
256 | 0 | { |
257 | 0 | REQUIRE(t != NULL && i != NULL && result != NULL); |
258 | 0 | 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 | 0 | if ((t->seconds > INT_MAX || i->seconds > INT_MAX) && |
267 | 0 | ((long long)t->seconds + i->seconds > UINT_MAX)) |
268 | 0 | return (ISC_R_RANGE); |
269 | | |
270 | 0 | result->seconds = t->seconds + i->seconds; |
271 | 0 | result->nanoseconds = t->nanoseconds + i->nanoseconds; |
272 | 0 | if (result->nanoseconds >= NS_PER_S) { |
273 | 0 | result->seconds++; |
274 | 0 | result->nanoseconds -= NS_PER_S; |
275 | 0 | } |
276 | |
|
277 | 0 | return (ISC_R_SUCCESS); |
278 | 0 | } |
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 | 0 | { |
284 | 0 | REQUIRE(t != NULL && i != NULL && result != NULL); |
285 | 0 | INSIST(t->nanoseconds < NS_PER_S && i->nanoseconds < NS_PER_S); |
286 | | |
287 | 0 | if ((unsigned int)t->seconds < i->seconds || |
288 | 0 | ((unsigned int)t->seconds == i->seconds && |
289 | 0 | t->nanoseconds < i->nanoseconds)) |
290 | 0 | return (ISC_R_RANGE); |
291 | | |
292 | 0 | result->seconds = t->seconds - i->seconds; |
293 | 0 | if (t->nanoseconds >= i->nanoseconds) |
294 | 0 | result->nanoseconds = t->nanoseconds - i->nanoseconds; |
295 | 0 | else { |
296 | 0 | result->nanoseconds = NS_PER_S - i->nanoseconds + |
297 | 0 | t->nanoseconds; |
298 | 0 | result->seconds--; |
299 | 0 | } |
300 | |
|
301 | 0 | return (ISC_R_SUCCESS); |
302 | 0 | } |
303 | | |
304 | | isc_uint64_t |
305 | 0 | isc_time_microdiff(const isc_time_t *t1, const isc_time_t *t2) { |
306 | 0 | isc_uint64_t i1, i2, i3; |
307 | |
|
308 | 0 | REQUIRE(t1 != NULL && t2 != NULL); |
309 | 0 | INSIST(t1->nanoseconds < NS_PER_S && t2->nanoseconds < NS_PER_S); |
310 | | |
311 | 0 | i1 = (isc_uint64_t)t1->seconds * NS_PER_S + t1->nanoseconds; |
312 | 0 | i2 = (isc_uint64_t)t2->seconds * NS_PER_S + t2->nanoseconds; |
313 | |
|
314 | 0 | if (i1 <= i2) |
315 | 0 | return (0); |
316 | | |
317 | 0 | i3 = i1 - i2; |
318 | | |
319 | | /* |
320 | | * Convert to microseconds. |
321 | | */ |
322 | 0 | i3 /= NS_PER_US; |
323 | |
|
324 | 0 | return (i3); |
325 | 0 | } |
326 | | |
327 | | isc_uint32_t |
328 | 0 | isc_time_seconds(const isc_time_t *t) { |
329 | 0 | REQUIRE(t != NULL); |
330 | 0 | INSIST(t->nanoseconds < NS_PER_S); |
331 | | |
332 | 0 | return ((isc_uint32_t)t->seconds); |
333 | 0 | } |
334 | | |
335 | | isc_result_t |
336 | 0 | isc_time_secondsastimet(const isc_time_t *t, time_t *secondsp) { |
337 | 0 | time_t seconds; |
338 | |
|
339 | 0 | REQUIRE(t != NULL); |
340 | 0 | INSIST(t->nanoseconds < NS_PER_S); |
341 | | |
342 | | /* |
343 | | * Ensure that the number of seconds represented by t->seconds |
344 | | * can be represented by a time_t. Since t->seconds is an unsigned |
345 | | * int and since time_t is mostly opaque, this is trickier than |
346 | | * it seems. (This standardized opaqueness of time_t is *very* |
347 | | * frustrating; time_t is not even limited to being an integral |
348 | | * type.) |
349 | | * |
350 | | * The mission, then, is to avoid generating any kind of warning |
351 | | * about "signed versus unsigned" while trying to determine if the |
352 | | * the unsigned int t->seconds is out range for tv_sec, which is |
353 | | * pretty much only true if time_t is a signed integer of the same |
354 | | * size as the return value of isc_time_seconds. |
355 | | * |
356 | | * If the paradox in the if clause below is true, t->seconds is out |
357 | | * of range for time_t. |
358 | | */ |
359 | 0 | seconds = (time_t)t->seconds; |
360 | |
|
361 | 0 | INSIST(sizeof(unsigned int) == sizeof(isc_uint32_t)); |
362 | 0 | INSIST(sizeof(time_t) >= sizeof(isc_uint32_t)); |
363 | | |
364 | 0 | if (t->seconds > (~0U>>1) && seconds <= (time_t)(~0U>>1)) |
365 | 0 | return (ISC_R_RANGE); |
366 | | |
367 | 0 | *secondsp = seconds; |
368 | |
|
369 | 0 | return (ISC_R_SUCCESS); |
370 | 0 | } |
371 | | |
372 | | isc_uint32_t |
373 | 0 | isc_time_nanoseconds(const isc_time_t *t) { |
374 | 0 | REQUIRE(t != NULL); |
375 | | |
376 | 0 | ENSURE(t->nanoseconds < NS_PER_S); |
377 | | |
378 | 0 | return ((isc_uint32_t)t->nanoseconds); |
379 | 0 | } |
380 | | |
381 | | void |
382 | 0 | isc_time_formattimestamp(const isc_time_t *t, char *buf, unsigned int len) { |
383 | 0 | time_t now; |
384 | 0 | unsigned int flen; |
385 | |
|
386 | 0 | REQUIRE(len > 0); |
387 | | |
388 | 0 | now = (time_t) t->seconds; |
389 | 0 | flen = strftime(buf, len, "%d-%b-%Y %X", localtime(&now)); |
390 | 0 | INSIST(flen < len); |
391 | 0 | if (flen != 0) |
392 | 0 | snprintf(buf + flen, len - flen, |
393 | 0 | ".%03u", t->nanoseconds / 1000000); |
394 | 0 | else |
395 | 0 | snprintf(buf, len, "99-Bad-9999 99:99:99.999"); |
396 | 0 | } |
397 | | |
398 | | void |
399 | 0 | isc_time_formathttptimestamp(const isc_time_t *t, char *buf, unsigned int len) { |
400 | 0 | time_t now; |
401 | 0 | unsigned int flen; |
402 | |
|
403 | 0 | REQUIRE(len > 0); |
404 | | |
405 | 0 | now = (time_t)t->seconds; |
406 | 0 | flen = strftime(buf, len, "%a, %d %b %Y %H:%M:%S GMT", gmtime(&now)); |
407 | 0 | INSIST(flen < len); |
408 | 0 | } |
409 | | |
410 | | void |
411 | 0 | isc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len) { |
412 | 0 | time_t now; |
413 | 0 | unsigned int flen; |
414 | |
|
415 | 0 | REQUIRE(len > 0); |
416 | | |
417 | 0 | now = (time_t)t->seconds; |
418 | 0 | flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%SZ", gmtime(&now)); |
419 | 0 | INSIST(flen < len); |
420 | 0 | } |