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 57static isc_interval_t zero_interval = { 0, 0 }; 58isc_interval_t *isc_interval_zero = &zero_interval; 59 60#if ISC_FIX_TV_USEC 61static inline void 62fix_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 86void 87isc_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 97isc_boolean_t 98isc_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 113static isc_time_t epoch = { 0, 0 }; 114isc_time_t *isc_time_epoch = &epoch; 115 116void 117isc_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 125void 126isc_time_settoepoch(isc_time_t *t) { 127 REQUIRE(t != NULL); 128 129 t->seconds = 0; 130 t->nanoseconds = 0; 131} 132 133isc_boolean_t 134isc_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 145isc_result_t 146isc_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 187isc_result_t 188isc_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 238int 239isc_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 254isc_result_t 255isc_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 280isc_result_t 281isc_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 304isc_uint64_t 305isc_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 327isc_uint32_t 328isc_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 335isc_result_t 336isc_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 390isc_uint32_t 391isc_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 399void 400isc_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 416void 417isc_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 428void 429isc_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} 439