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