1/* $NetBSD: time.c,v 1.2 2024/08/18 20:47:16 christos Exp $ */ 2 3/* 4 * Copyright (C) 2004-2008, 2011, 2012 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 <syslog.h> 29#include <time.h> 30 31#include <sys/time.h> /* Required for struct timeval on some platforms. */ 32 33#include <isc/log.h> 34#include <isc/print.h> 35#include <isc/strerror.h> 36#include <isc/string.h> 37#include <isc/time.h> 38#include <isc/util.h> 39 40#define NS_PER_S 1000000000 /*%< Nanoseconds per second. */ 41#define NS_PER_US 1000 /*%< Nanoseconds per microsecond. */ 42#define US_PER_S 1000000 /*%< Microseconds per second. */ 43 44/* 45 * All of the INSIST()s checks of nanoseconds < NS_PER_S are for 46 * consistency checking of the type. In lieu of magic numbers, it 47 * is the best we've got. The check is only performed on functions which 48 * need an initialized type. 49 */ 50 51#ifndef ISC_FIX_TV_USEC 52#define ISC_FIX_TV_USEC 1 53#endif 54 55/*% 56 *** Intervals 57 ***/ 58 59static isc_interval_t zero_interval = { 0, 0 }; 60isc_interval_t *isc_interval_zero = &zero_interval; 61 62#if ISC_FIX_TV_USEC 63static inline void 64fix_tv_usec(struct timeval *tv) { 65 isc_boolean_t fixed = ISC_FALSE; 66 67 if (tv->tv_usec < 0) { 68 fixed = ISC_TRUE; 69 do { 70 tv->tv_sec -= 1; 71 tv->tv_usec += US_PER_S; 72 } while (tv->tv_usec < 0); 73 } else if (tv->tv_usec >= US_PER_S) { 74 fixed = ISC_TRUE; 75 do { 76 tv->tv_sec += 1; 77 tv->tv_usec -= US_PER_S; 78 } while (tv->tv_usec >=US_PER_S); 79 } 80 /* 81 * Call syslog directly as was are called from the logging functions. 82 */ 83 if (fixed) 84 (void)syslog(LOG_ERR, "gettimeofday returned bad tv_usec: corrected"); 85} 86#endif 87 88void 89isc_interval_set(isc_interval_t *i, 90 unsigned int seconds, unsigned int nanoseconds) 91{ 92 REQUIRE(i != NULL); 93 REQUIRE(nanoseconds < NS_PER_S); 94 95 i->seconds = seconds; 96 i->nanoseconds = nanoseconds; 97} 98 99isc_boolean_t 100isc_interval_iszero(const isc_interval_t *i) { 101 REQUIRE(i != NULL); 102 INSIST(i->nanoseconds < NS_PER_S); 103 104 if (i->seconds == 0 && i->nanoseconds == 0) 105 return (ISC_TRUE); 106 107 return (ISC_FALSE); 108} 109 110 111/*** 112 *** Absolute Times 113 ***/ 114 115static isc_time_t epoch = { 0, 0 }; 116isc_time_t *isc_time_epoch = &epoch; 117 118void 119isc_time_set(isc_time_t *t, unsigned int seconds, unsigned int nanoseconds) { 120 REQUIRE(t != NULL); 121 REQUIRE(nanoseconds < NS_PER_S); 122 123 t->seconds = seconds; 124 t->nanoseconds = nanoseconds; 125} 126 127void 128isc_time_settoepoch(isc_time_t *t) { 129 REQUIRE(t != NULL); 130 131 t->seconds = 0; 132 t->nanoseconds = 0; 133} 134 135isc_boolean_t 136isc_time_isepoch(const isc_time_t *t) { 137 REQUIRE(t != NULL); 138 INSIST(t->nanoseconds < NS_PER_S); 139 140 if (t->seconds == 0 && t->nanoseconds == 0) 141 return (ISC_TRUE); 142 143 return (ISC_FALSE); 144} 145 146 147isc_result_t 148isc_time_now(isc_time_t *t) { 149 struct timeval tv; 150 char strbuf[ISC_STRERRORSIZE]; 151 152 REQUIRE(t != NULL); 153 154 if (gettimeofday(&tv, NULL) == -1) { 155 isc__strerror(errno, strbuf, sizeof(strbuf)); 156 UNEXPECTED_ERROR(__FILE__, __LINE__, "%s", strbuf); 157 return (ISC_R_UNEXPECTED); 158 } 159 160 /* 161 * Does POSIX guarantee the signedness of tv_sec and tv_usec? If not, 162 * then this test will generate warnings for platforms on which it is 163 * unsigned. In any event, the chances of any of these problems 164 * happening are pretty much zero, but since the libisc library ensures 165 * certain things to be true ... 166 */ 167#if ISC_FIX_TV_USEC 168 fix_tv_usec(&tv); 169 if (tv.tv_sec < 0) 170 return (ISC_R_UNEXPECTED); 171#else 172 if (tv.tv_sec < 0 || tv.tv_usec < 0 || tv.tv_usec >= US_PER_S) 173 return (ISC_R_UNEXPECTED); 174#endif 175 176 /* 177 * Ensure the tv_sec value fits in t->seconds. 178 */ 179 if (sizeof(tv.tv_sec) > sizeof(t->seconds) && 180 ((tv.tv_sec | (unsigned int)-1) ^ (unsigned int)-1) != 0U) 181 return (ISC_R_RANGE); 182 183 t->seconds = tv.tv_sec; 184 t->nanoseconds = tv.tv_usec * NS_PER_US; 185 186 return (ISC_R_SUCCESS); 187} 188 189isc_result_t 190isc_time_nowplusinterval(isc_time_t *t, const isc_interval_t *i) { 191 struct timeval tv; 192 char strbuf[ISC_STRERRORSIZE]; 193 194 REQUIRE(t != NULL); 195 REQUIRE(i != NULL); 196 INSIST(i->nanoseconds < NS_PER_S); 197 198 if (gettimeofday(&tv, NULL) == -1) { 199 isc__strerror(errno, strbuf, sizeof(strbuf)); 200 UNEXPECTED_ERROR(__FILE__, __LINE__, "%s", strbuf); 201 return (ISC_R_UNEXPECTED); 202 } 203 204 /* 205 * Does POSIX guarantee the signedness of tv_sec and tv_usec? If not, 206 * then this test will generate warnings for platforms on which it is 207 * unsigned. In any event, the chances of any of these problems 208 * happening are pretty much zero, but since the libisc library ensures 209 * certain things to be true ... 210 */ 211#if ISC_FIX_TV_USEC 212 fix_tv_usec(&tv); 213 if (tv.tv_sec < 0) 214 return (ISC_R_UNEXPECTED); 215#else 216 if (tv.tv_sec < 0 || tv.tv_usec < 0 || tv.tv_usec >= US_PER_S) 217 return (ISC_R_UNEXPECTED); 218#endif 219 220 /* 221 * Ensure the resulting seconds value fits in the size of an 222 * unsigned int. (It is written this way as a slight optimization; 223 * note that even if both values == INT_MAX, then when added 224 * and getting another 1 added below the result is UINT_MAX.) 225 */ 226 if ((tv.tv_sec > INT_MAX || i->seconds > INT_MAX) && 227 ((long long)tv.tv_sec + i->seconds > UINT_MAX)) 228 return (ISC_R_RANGE); 229 230 t->seconds = tv.tv_sec + i->seconds; 231 t->nanoseconds = tv.tv_usec * NS_PER_US + i->nanoseconds; 232 if (t->nanoseconds >= NS_PER_S) { 233 t->seconds++; 234 t->nanoseconds -= NS_PER_S; 235 } 236 237 return (ISC_R_SUCCESS); 238} 239 240int 241isc_time_compare(const isc_time_t *t1, const isc_time_t *t2) { 242 REQUIRE(t1 != NULL && t2 != NULL); 243 INSIST(t1->nanoseconds < NS_PER_S && t2->nanoseconds < NS_PER_S); 244 245 if (t1->seconds < t2->seconds) 246 return (-1); 247 if (t1->seconds > t2->seconds) 248 return (1); 249 if (t1->nanoseconds < t2->nanoseconds) 250 return (-1); 251 if (t1->nanoseconds > t2->nanoseconds) 252 return (1); 253 return (0); 254} 255 256isc_result_t 257isc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result) 258{ 259 REQUIRE(t != NULL && i != NULL && result != NULL); 260 INSIST(t->nanoseconds < NS_PER_S && i->nanoseconds < NS_PER_S); 261 262 /* 263 * Ensure the resulting seconds value fits in the size of an 264 * unsigned int. (It is written this way as a slight optimization; 265 * note that even if both values == INT_MAX, then when added 266 * and getting another 1 added below the result is UINT_MAX.) 267 */ 268 if ((t->seconds > INT_MAX || i->seconds > INT_MAX) && 269 ((long long)t->seconds + i->seconds > UINT_MAX)) 270 return (ISC_R_RANGE); 271 272 result->seconds = t->seconds + i->seconds; 273 result->nanoseconds = t->nanoseconds + i->nanoseconds; 274 if (result->nanoseconds >= NS_PER_S) { 275 result->seconds++; 276 result->nanoseconds -= NS_PER_S; 277 } 278 279 return (ISC_R_SUCCESS); 280} 281 282isc_result_t 283isc_time_subtract(const isc_time_t *t, const isc_interval_t *i, 284 isc_time_t *result) 285{ 286 REQUIRE(t != NULL && i != NULL && result != NULL); 287 INSIST(t->nanoseconds < NS_PER_S && i->nanoseconds < NS_PER_S); 288 289 if ((unsigned int)t->seconds < i->seconds || 290 ((unsigned int)t->seconds == i->seconds && 291 t->nanoseconds < i->nanoseconds)) 292 return (ISC_R_RANGE); 293 294 result->seconds = t->seconds - i->seconds; 295 if (t->nanoseconds >= i->nanoseconds) 296 result->nanoseconds = t->nanoseconds - i->nanoseconds; 297 else { 298 result->nanoseconds = NS_PER_S - i->nanoseconds + 299 t->nanoseconds; 300 result->seconds--; 301 } 302 303 return (ISC_R_SUCCESS); 304} 305 306isc_uint64_t 307isc_time_microdiff(const isc_time_t *t1, const isc_time_t *t2) { 308 isc_uint64_t i1, i2, i3; 309 310 REQUIRE(t1 != NULL && t2 != NULL); 311 INSIST(t1->nanoseconds < NS_PER_S && t2->nanoseconds < NS_PER_S); 312 313 i1 = (isc_uint64_t)t1->seconds * NS_PER_S + t1->nanoseconds; 314 i2 = (isc_uint64_t)t2->seconds * NS_PER_S + t2->nanoseconds; 315 316 if (i1 <= i2) 317 return (0); 318 319 i3 = i1 - i2; 320 321 /* 322 * Convert to microseconds. 323 */ 324 i3 /= NS_PER_US; 325 326 return (i3); 327} 328 329isc_uint32_t 330isc_time_seconds(const isc_time_t *t) { 331 REQUIRE(t != NULL); 332 INSIST(t->nanoseconds < NS_PER_S); 333 334 return ((isc_uint32_t)t->seconds); 335} 336 337isc_result_t 338isc_time_secondsastimet(const isc_time_t *t, time_t *secondsp) { 339 time_t seconds; 340 341 REQUIRE(t != NULL); 342 INSIST(t->nanoseconds < NS_PER_S); 343 344 /* 345 * Ensure that the number of seconds represented by t->seconds 346 * can be represented by a time_t. Since t->seconds is an unsigned 347 * int and since time_t is mostly opaque, this is trickier than 348 * it seems. (This standardized opaqueness of time_t is *very* 349 * frustrating; time_t is not even limited to being an integral 350 * type.) 351 * 352 * The mission, then, is to avoid generating any kind of warning 353 * about "signed versus unsigned" while trying to determine if the 354 * the unsigned int t->seconds is out range for tv_sec, which is 355 * pretty much only true if time_t is a signed integer of the same 356 * size as the return value of isc_time_seconds. 357 * 358 * If the paradox in the if clause below is true, t->seconds is out 359 * of range for time_t. 360 */ 361 seconds = (time_t)t->seconds; 362 363 INSIST(sizeof(unsigned int) == sizeof(isc_uint32_t)); 364 INSIST(sizeof(time_t) >= sizeof(isc_uint32_t)); 365 366 if (t->seconds > (~0U>>1) && seconds <= (time_t)(~0U>>1)) 367 return (ISC_R_RANGE); 368 369 *secondsp = seconds; 370 371 return (ISC_R_SUCCESS); 372} 373 374isc_uint32_t 375isc_time_nanoseconds(const isc_time_t *t) { 376 REQUIRE(t != NULL); 377 378 ENSURE(t->nanoseconds < NS_PER_S); 379 380 return ((isc_uint32_t)t->nanoseconds); 381} 382 383void 384isc_time_formattimestamp(const isc_time_t *t, char *buf, unsigned int len) { 385 time_t now; 386 unsigned int flen; 387 388 REQUIRE(len > 0); 389 390 now = (time_t) t->seconds; 391 flen = strftime(buf, len, "%d-%b-%Y %X", localtime(&now)); 392 INSIST(flen < len); 393 if (flen != 0) 394 snprintf(buf + flen, len - flen, 395 ".%03u", t->nanoseconds / 1000000); 396 else 397 snprintf(buf, len, "99-Bad-9999 99:99:99.999"); 398} 399 400void 401isc_time_formathttptimestamp(const isc_time_t *t, char *buf, unsigned int len) { 402 time_t now; 403 unsigned int flen; 404 405 REQUIRE(len > 0); 406 407 now = (time_t)t->seconds; 408 flen = strftime(buf, len, "%a, %d %b %Y %H:%M:%S GMT", gmtime(&now)); 409 INSIST(flen < len); 410} 411 412void 413isc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len) { 414 time_t now; 415 unsigned int flen; 416 417 REQUIRE(len > 0); 418 419 now = (time_t)t->seconds; 420 flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%SZ", gmtime(&now)); 421 INSIST(flen < len); 422} 423