1290001Sglebius/*
2290001Sglebius * Copyright (C) 2004-2008, 2011, 2012  Internet Systems Consortium, Inc. ("ISC")
3290001Sglebius * Copyright (C) 1998-2001, 2003  Internet Software Consortium.
4290001Sglebius *
5290001Sglebius * Permission to use, copy, modify, and/or distribute this software for any
6290001Sglebius * purpose with or without fee is hereby granted, provided that the above
7290001Sglebius * copyright notice and this permission notice appear in all copies.
8290001Sglebius *
9290001Sglebius * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10290001Sglebius * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11290001Sglebius * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12290001Sglebius * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13290001Sglebius * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14290001Sglebius * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15290001Sglebius * PERFORMANCE OF THIS SOFTWARE.
16290001Sglebius */
17290001Sglebius
18290001Sglebius/* $Id$ */
19290001Sglebius
20290001Sglebius/*! \file */
21290001Sglebius
22290001Sglebius#include <config.h>
23290001Sglebius
24290001Sglebius#include <errno.h>
25290001Sglebius#include <limits.h>
26290001Sglebius#include <syslog.h>
27290001Sglebius#include <time.h>
28290001Sglebius
29290001Sglebius#include <sys/time.h>	/* Required for struct timeval on some platforms. */
30290001Sglebius
31290001Sglebius#include <isc/log.h>
32290001Sglebius#include <isc/print.h>
33290001Sglebius#include <isc/strerror.h>
34290001Sglebius#include <isc/string.h>
35290001Sglebius#include <isc/time.h>
36290001Sglebius#include <isc/util.h>
37290001Sglebius
38290001Sglebius#define NS_PER_S	1000000000	/*%< Nanoseconds per second. */
39290001Sglebius#define NS_PER_US	1000		/*%< Nanoseconds per microsecond. */
40290001Sglebius#define US_PER_S	1000000		/*%< Microseconds per second. */
41290001Sglebius
42290001Sglebius/*
43290001Sglebius * All of the INSIST()s checks of nanoseconds < NS_PER_S are for
44290001Sglebius * consistency checking of the type. In lieu of magic numbers, it
45290001Sglebius * is the best we've got.  The check is only performed on functions which
46290001Sglebius * need an initialized type.
47290001Sglebius */
48290001Sglebius
49290001Sglebius#ifndef ISC_FIX_TV_USEC
50290001Sglebius#define ISC_FIX_TV_USEC 1
51290001Sglebius#endif
52290001Sglebius
53290001Sglebius/*%
54290001Sglebius *** Intervals
55290001Sglebius ***/
56290001Sglebius
57290001Sglebiusstatic isc_interval_t zero_interval = { 0, 0 };
58290001Sglebiusisc_interval_t *isc_interval_zero = &zero_interval;
59290001Sglebius
60290001Sglebius#if ISC_FIX_TV_USEC
61290001Sglebiusstatic inline void
62290001Sglebiusfix_tv_usec(struct timeval *tv) {
63290001Sglebius	isc_boolean_t fixed = ISC_FALSE;
64290001Sglebius
65290001Sglebius	if (tv->tv_usec < 0) {
66290001Sglebius		fixed = ISC_TRUE;
67290001Sglebius		do {
68290001Sglebius			tv->tv_sec -= 1;
69290001Sglebius			tv->tv_usec += US_PER_S;
70290001Sglebius		} while (tv->tv_usec < 0);
71290001Sglebius	} else if (tv->tv_usec >= US_PER_S) {
72290001Sglebius		fixed = ISC_TRUE;
73290001Sglebius		do {
74290001Sglebius			tv->tv_sec += 1;
75290001Sglebius			tv->tv_usec -= US_PER_S;
76290001Sglebius		} while (tv->tv_usec >=US_PER_S);
77290001Sglebius	}
78290001Sglebius	/*
79290001Sglebius	 * Call syslog directly as was are called from the logging functions.
80290001Sglebius	 */
81290001Sglebius	if (fixed)
82290001Sglebius		(void)syslog(LOG_ERR, "gettimeofday returned bad tv_usec: corrected");
83290001Sglebius}
84290001Sglebius#endif
85290001Sglebius
86290001Sglebiusvoid
87290001Sglebiusisc_interval_set(isc_interval_t *i,
88290001Sglebius		 unsigned int seconds, unsigned int nanoseconds)
89290001Sglebius{
90290001Sglebius	REQUIRE(i != NULL);
91290001Sglebius	REQUIRE(nanoseconds < NS_PER_S);
92290001Sglebius
93290001Sglebius	i->seconds = seconds;
94290001Sglebius	i->nanoseconds = nanoseconds;
95290001Sglebius}
96290001Sglebius
97290001Sglebiusisc_boolean_t
98290001Sglebiusisc_interval_iszero(const isc_interval_t *i) {
99290001Sglebius	REQUIRE(i != NULL);
100290001Sglebius	INSIST(i->nanoseconds < NS_PER_S);
101290001Sglebius
102290001Sglebius	if (i->seconds == 0 && i->nanoseconds == 0)
103290001Sglebius		return (ISC_TRUE);
104290001Sglebius
105290001Sglebius	return (ISC_FALSE);
106290001Sglebius}
107290001Sglebius
108290001Sglebius
109290001Sglebius/***
110290001Sglebius *** Absolute Times
111290001Sglebius ***/
112290001Sglebius
113290001Sglebiusstatic isc_time_t epoch = { 0, 0 };
114290001Sglebiusisc_time_t *isc_time_epoch = &epoch;
115290001Sglebius
116290001Sglebiusvoid
117290001Sglebiusisc_time_set(isc_time_t *t, unsigned int seconds, unsigned int nanoseconds) {
118290001Sglebius	REQUIRE(t != NULL);
119290001Sglebius	REQUIRE(nanoseconds < NS_PER_S);
120290001Sglebius
121290001Sglebius	t->seconds = seconds;
122290001Sglebius	t->nanoseconds = nanoseconds;
123290001Sglebius}
124290001Sglebius
125290001Sglebiusvoid
126290001Sglebiusisc_time_settoepoch(isc_time_t *t) {
127290001Sglebius	REQUIRE(t != NULL);
128290001Sglebius
129290001Sglebius	t->seconds = 0;
130290001Sglebius	t->nanoseconds = 0;
131290001Sglebius}
132290001Sglebius
133290001Sglebiusisc_boolean_t
134290001Sglebiusisc_time_isepoch(const isc_time_t *t) {
135290001Sglebius	REQUIRE(t != NULL);
136290001Sglebius	INSIST(t->nanoseconds < NS_PER_S);
137290001Sglebius
138290001Sglebius	if (t->seconds == 0 && t->nanoseconds == 0)
139290001Sglebius		return (ISC_TRUE);
140290001Sglebius
141290001Sglebius	return (ISC_FALSE);
142290001Sglebius}
143290001Sglebius
144290001Sglebius
145290001Sglebiusisc_result_t
146290001Sglebiusisc_time_now(isc_time_t *t) {
147290001Sglebius	struct timeval tv;
148290001Sglebius	char strbuf[ISC_STRERRORSIZE];
149290001Sglebius
150290001Sglebius	REQUIRE(t != NULL);
151290001Sglebius
152290001Sglebius	if (gettimeofday(&tv, NULL) == -1) {
153290001Sglebius		isc__strerror(errno, strbuf, sizeof(strbuf));
154290001Sglebius		UNEXPECTED_ERROR(__FILE__, __LINE__, "%s", strbuf);
155290001Sglebius		return (ISC_R_UNEXPECTED);
156290001Sglebius	}
157290001Sglebius
158290001Sglebius	/*
159290001Sglebius	 * Does POSIX guarantee the signedness of tv_sec and tv_usec?  If not,
160290001Sglebius	 * then this test will generate warnings for platforms on which it is
161290001Sglebius	 * unsigned.  In any event, the chances of any of these problems
162290001Sglebius	 * happening are pretty much zero, but since the libisc library ensures
163290001Sglebius	 * certain things to be true ...
164290001Sglebius	 */
165290001Sglebius#if ISC_FIX_TV_USEC
166290001Sglebius	fix_tv_usec(&tv);
167290001Sglebius	if (tv.tv_sec < 0)
168290001Sglebius		return (ISC_R_UNEXPECTED);
169290001Sglebius#else
170290001Sglebius	if (tv.tv_sec < 0 || tv.tv_usec < 0 || tv.tv_usec >= US_PER_S)
171290001Sglebius		return (ISC_R_UNEXPECTED);
172290001Sglebius#endif
173290001Sglebius
174290001Sglebius	/*
175290001Sglebius	 * Ensure the tv_sec value fits in t->seconds.
176290001Sglebius	 */
177290001Sglebius	if (sizeof(tv.tv_sec) > sizeof(t->seconds) &&
178290001Sglebius	    ((tv.tv_sec | (unsigned int)-1) ^ (unsigned int)-1) != 0U)
179290001Sglebius		return (ISC_R_RANGE);
180290001Sglebius
181290001Sglebius	t->seconds = tv.tv_sec;
182290001Sglebius	t->nanoseconds = tv.tv_usec * NS_PER_US;
183290001Sglebius
184290001Sglebius	return (ISC_R_SUCCESS);
185290001Sglebius}
186290001Sglebius
187290001Sglebiusisc_result_t
188290001Sglebiusisc_time_nowplusinterval(isc_time_t *t, const isc_interval_t *i) {
189290001Sglebius	struct timeval tv;
190290001Sglebius	char strbuf[ISC_STRERRORSIZE];
191290001Sglebius
192290001Sglebius	REQUIRE(t != NULL);
193290001Sglebius	REQUIRE(i != NULL);
194290001Sglebius	INSIST(i->nanoseconds < NS_PER_S);
195290001Sglebius
196290001Sglebius	if (gettimeofday(&tv, NULL) == -1) {
197290001Sglebius		isc__strerror(errno, strbuf, sizeof(strbuf));
198290001Sglebius		UNEXPECTED_ERROR(__FILE__, __LINE__, "%s", strbuf);
199290001Sglebius		return (ISC_R_UNEXPECTED);
200290001Sglebius	}
201290001Sglebius
202290001Sglebius	/*
203290001Sglebius	 * Does POSIX guarantee the signedness of tv_sec and tv_usec?  If not,
204290001Sglebius	 * then this test will generate warnings for platforms on which it is
205290001Sglebius	 * unsigned.  In any event, the chances of any of these problems
206290001Sglebius	 * happening are pretty much zero, but since the libisc library ensures
207290001Sglebius	 * certain things to be true ...
208290001Sglebius	 */
209290001Sglebius#if ISC_FIX_TV_USEC
210290001Sglebius	fix_tv_usec(&tv);
211290001Sglebius	if (tv.tv_sec < 0)
212290001Sglebius		return (ISC_R_UNEXPECTED);
213290001Sglebius#else
214290001Sglebius	if (tv.tv_sec < 0 || tv.tv_usec < 0 || tv.tv_usec >= US_PER_S)
215290001Sglebius		return (ISC_R_UNEXPECTED);
216290001Sglebius#endif
217290001Sglebius
218290001Sglebius	/*
219290001Sglebius	 * Ensure the resulting seconds value fits in the size of an
220290001Sglebius	 * unsigned int.  (It is written this way as a slight optimization;
221290001Sglebius	 * note that even if both values == INT_MAX, then when added
222290001Sglebius	 * and getting another 1 added below the result is UINT_MAX.)
223290001Sglebius	 */
224290001Sglebius	if ((tv.tv_sec > INT_MAX || i->seconds > INT_MAX) &&
225290001Sglebius	    ((long long)tv.tv_sec + i->seconds > UINT_MAX))
226290001Sglebius		return (ISC_R_RANGE);
227290001Sglebius
228290001Sglebius	t->seconds = tv.tv_sec + i->seconds;
229290001Sglebius	t->nanoseconds = tv.tv_usec * NS_PER_US + i->nanoseconds;
230290001Sglebius	if (t->nanoseconds >= NS_PER_S) {
231290001Sglebius		t->seconds++;
232290001Sglebius		t->nanoseconds -= NS_PER_S;
233290001Sglebius	}
234290001Sglebius
235290001Sglebius	return (ISC_R_SUCCESS);
236290001Sglebius}
237290001Sglebius
238290001Sglebiusint
239290001Sglebiusisc_time_compare(const isc_time_t *t1, const isc_time_t *t2) {
240290001Sglebius	REQUIRE(t1 != NULL && t2 != NULL);
241290001Sglebius	INSIST(t1->nanoseconds < NS_PER_S && t2->nanoseconds < NS_PER_S);
242290001Sglebius
243290001Sglebius	if (t1->seconds < t2->seconds)
244290001Sglebius		return (-1);
245290001Sglebius	if (t1->seconds > t2->seconds)
246290001Sglebius		return (1);
247290001Sglebius	if (t1->nanoseconds < t2->nanoseconds)
248290001Sglebius		return (-1);
249290001Sglebius	if (t1->nanoseconds > t2->nanoseconds)
250290001Sglebius		return (1);
251290001Sglebius	return (0);
252290001Sglebius}
253290001Sglebius
254290001Sglebiusisc_result_t
255290001Sglebiusisc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result)
256290001Sglebius{
257290001Sglebius	REQUIRE(t != NULL && i != NULL && result != NULL);
258290001Sglebius	INSIST(t->nanoseconds < NS_PER_S && i->nanoseconds < NS_PER_S);
259290001Sglebius
260290001Sglebius	/*
261290001Sglebius	 * Ensure the resulting seconds value fits in the size of an
262290001Sglebius	 * unsigned int.  (It is written this way as a slight optimization;
263290001Sglebius	 * note that even if both values == INT_MAX, then when added
264290001Sglebius	 * and getting another 1 added below the result is UINT_MAX.)
265290001Sglebius	 */
266290001Sglebius	if ((t->seconds > INT_MAX || i->seconds > INT_MAX) &&
267290001Sglebius	    ((long long)t->seconds + i->seconds > UINT_MAX))
268290001Sglebius		return (ISC_R_RANGE);
269290001Sglebius
270290001Sglebius	result->seconds = t->seconds + i->seconds;
271290001Sglebius	result->nanoseconds = t->nanoseconds + i->nanoseconds;
272290001Sglebius	if (result->nanoseconds >= NS_PER_S) {
273290001Sglebius		result->seconds++;
274290001Sglebius		result->nanoseconds -= NS_PER_S;
275290001Sglebius	}
276290001Sglebius
277290001Sglebius	return (ISC_R_SUCCESS);
278290001Sglebius}
279290001Sglebius
280290001Sglebiusisc_result_t
281290001Sglebiusisc_time_subtract(const isc_time_t *t, const isc_interval_t *i,
282290001Sglebius		  isc_time_t *result)
283290001Sglebius{
284290001Sglebius	REQUIRE(t != NULL && i != NULL && result != NULL);
285290001Sglebius	INSIST(t->nanoseconds < NS_PER_S && i->nanoseconds < NS_PER_S);
286290001Sglebius
287290001Sglebius	if ((unsigned int)t->seconds < i->seconds ||
288290001Sglebius	    ((unsigned int)t->seconds == i->seconds &&
289290001Sglebius	     t->nanoseconds < i->nanoseconds))
290290001Sglebius	    return (ISC_R_RANGE);
291290001Sglebius
292290001Sglebius	result->seconds = t->seconds - i->seconds;
293290001Sglebius	if (t->nanoseconds >= i->nanoseconds)
294290001Sglebius		result->nanoseconds = t->nanoseconds - i->nanoseconds;
295290001Sglebius	else {
296290001Sglebius		result->nanoseconds = NS_PER_S - i->nanoseconds +
297290001Sglebius			t->nanoseconds;
298290001Sglebius		result->seconds--;
299290001Sglebius	}
300290001Sglebius
301290001Sglebius	return (ISC_R_SUCCESS);
302290001Sglebius}
303290001Sglebius
304290001Sglebiusisc_uint64_t
305290001Sglebiusisc_time_microdiff(const isc_time_t *t1, const isc_time_t *t2) {
306290001Sglebius	isc_uint64_t i1, i2, i3;
307290001Sglebius
308290001Sglebius	REQUIRE(t1 != NULL && t2 != NULL);
309290001Sglebius	INSIST(t1->nanoseconds < NS_PER_S && t2->nanoseconds < NS_PER_S);
310290001Sglebius
311290001Sglebius	i1 = (isc_uint64_t)t1->seconds * NS_PER_S + t1->nanoseconds;
312290001Sglebius	i2 = (isc_uint64_t)t2->seconds * NS_PER_S + t2->nanoseconds;
313290001Sglebius
314290001Sglebius	if (i1 <= i2)
315290001Sglebius		return (0);
316290001Sglebius
317290001Sglebius	i3 = i1 - i2;
318290001Sglebius
319290001Sglebius	/*
320290001Sglebius	 * Convert to microseconds.
321290001Sglebius	 */
322290001Sglebius	i3 /= NS_PER_US;
323290001Sglebius
324290001Sglebius	return (i3);
325290001Sglebius}
326290001Sglebius
327290001Sglebiusisc_uint32_t
328290001Sglebiusisc_time_seconds(const isc_time_t *t) {
329290001Sglebius	REQUIRE(t != NULL);
330290001Sglebius	INSIST(t->nanoseconds < NS_PER_S);
331290001Sglebius
332290001Sglebius	return ((isc_uint32_t)t->seconds);
333290001Sglebius}
334290001Sglebius
335290001Sglebiusisc_result_t
336290001Sglebiusisc_time_secondsastimet(const isc_time_t *t, time_t *secondsp) {
337290001Sglebius	time_t seconds;
338290001Sglebius
339290001Sglebius	REQUIRE(t != NULL);
340290001Sglebius	INSIST(t->nanoseconds < NS_PER_S);
341290001Sglebius
342290001Sglebius	/*
343290001Sglebius	 * Ensure that the number of seconds represented by t->seconds
344290001Sglebius	 * can be represented by a time_t.  Since t->seconds is an unsigned
345290001Sglebius	 * int and since time_t is mostly opaque, this is trickier than
346290001Sglebius	 * it seems.  (This standardized opaqueness of time_t is *very*
347290001Sglebius	 * frustrating; time_t is not even limited to being an integral
348290001Sglebius	 * type.)
349290001Sglebius	 *
350290001Sglebius	 * The mission, then, is to avoid generating any kind of warning
351290001Sglebius	 * about "signed versus unsigned" while trying to determine if the
352290001Sglebius	 * the unsigned int t->seconds is out range for tv_sec, which is
353290001Sglebius	 * pretty much only true if time_t is a signed integer of the same
354290001Sglebius	 * size as the return value of isc_time_seconds.
355290001Sglebius	 *
356290001Sglebius	 * If the paradox in the if clause below is true, t->seconds is out
357290001Sglebius	 * of range for time_t.
358290001Sglebius	 */
359290001Sglebius	seconds = (time_t)t->seconds;
360290001Sglebius
361290001Sglebius	INSIST(sizeof(unsigned int) == sizeof(isc_uint32_t));
362290001Sglebius	INSIST(sizeof(time_t) >= sizeof(isc_uint32_t));
363290001Sglebius
364290001Sglebius	if (t->seconds > (~0U>>1) && seconds <= (time_t)(~0U>>1))
365290001Sglebius		return (ISC_R_RANGE);
366290001Sglebius
367290001Sglebius	*secondsp = seconds;
368290001Sglebius
369290001Sglebius	return (ISC_R_SUCCESS);
370290001Sglebius}
371290001Sglebius
372290001Sglebiusisc_uint32_t
373290001Sglebiusisc_time_nanoseconds(const isc_time_t *t) {
374290001Sglebius	REQUIRE(t != NULL);
375290001Sglebius
376290001Sglebius	ENSURE(t->nanoseconds < NS_PER_S);
377290001Sglebius
378290001Sglebius	return ((isc_uint32_t)t->nanoseconds);
379290001Sglebius}
380290001Sglebius
381290001Sglebiusvoid
382290001Sglebiusisc_time_formattimestamp(const isc_time_t *t, char *buf, unsigned int len) {
383290001Sglebius	time_t now;
384290001Sglebius	unsigned int flen;
385290001Sglebius
386290001Sglebius	REQUIRE(len > 0);
387290001Sglebius
388290001Sglebius	now = (time_t) t->seconds;
389290001Sglebius	flen = strftime(buf, len, "%d-%b-%Y %X", localtime(&now));
390290001Sglebius	INSIST(flen < len);
391290001Sglebius	if (flen != 0)
392290001Sglebius		snprintf(buf + flen, len - flen,
393290001Sglebius			 ".%03u", t->nanoseconds / 1000000);
394290001Sglebius	else
395290001Sglebius		snprintf(buf, len, "99-Bad-9999 99:99:99.999");
396290001Sglebius}
397290001Sglebius
398290001Sglebiusvoid
399290001Sglebiusisc_time_formathttptimestamp(const isc_time_t *t, char *buf, unsigned int len) {
400290001Sglebius	time_t now;
401290001Sglebius	unsigned int flen;
402290001Sglebius
403290001Sglebius	REQUIRE(len > 0);
404290001Sglebius
405290001Sglebius	now = (time_t)t->seconds;
406290001Sglebius	flen = strftime(buf, len, "%a, %d %b %Y %H:%M:%S GMT", gmtime(&now));
407290001Sglebius	INSIST(flen < len);
408290001Sglebius}
409290001Sglebius
410290001Sglebiusvoid
411290001Sglebiusisc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len) {
412290001Sglebius	time_t now;
413290001Sglebius	unsigned int flen;
414290001Sglebius
415290001Sglebius	REQUIRE(len > 0);
416290001Sglebius
417290001Sglebius	now = (time_t)t->seconds;
418290001Sglebius	flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%SZ", gmtime(&now));
419290001Sglebius	INSIST(flen < len);
420290001Sglebius}
421