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