time.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004-2008, 2011, 2012, 2014, 2015  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 1998-2001, 2003  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /* $Id$ */
00019 
00020 /*! \file */
00021 
00022 #include <config.h>
00023 
00024 #include <errno.h>
00025 #include <limits.h>
00026 #include <stdlib.h>
00027 #include <syslog.h>
00028 #include <time.h>
00029 
00030 #include <sys/time.h>   /* Required for struct timeval on some platforms. */
00031 
00032 #include <isc/log.h>
00033 #include <isc/print.h>
00034 #include <isc/strerror.h>
00035 #include <isc/string.h>
00036 #include <isc/time.h>
00037 #include <isc/tm.h>
00038 #include <isc/util.h>
00039 
00040 #define NS_PER_S        1000000000      /*%< Nanoseconds per second. */
00041 #define NS_PER_US       1000            /*%< Nanoseconds per microsecond. */
00042 #define US_PER_S        1000000         /*%< Microseconds per second. */
00043 
00044 /*
00045  * All of the INSIST()s checks of nanoseconds < NS_PER_S are for
00046  * consistency checking of the type. In lieu of magic numbers, it
00047  * is the best we've got.  The check is only performed on functions which
00048  * need an initialized type.
00049  */
00050 
00051 #ifndef ISC_FIX_TV_USEC
00052 #define ISC_FIX_TV_USEC 1
00053 #endif
00054 
00055 /*%
00056  *** Intervals
00057  ***/
00058 
00059 static const isc_interval_t zero_interval = { 0, 0 };
00060 const isc_interval_t * const isc_interval_zero = &zero_interval;
00061 
00062 #if ISC_FIX_TV_USEC
00063 static inline void
00064 fix_tv_usec(struct timeval *tv) {
00065         isc_boolean_t fixed = ISC_FALSE;
00066 
00067         if (tv->tv_usec < 0) {
00068                 fixed = ISC_TRUE;
00069                 do {
00070                         tv->tv_sec -= 1;
00071                         tv->tv_usec += US_PER_S;
00072                 } while (tv->tv_usec < 0);
00073         } else if (tv->tv_usec >= US_PER_S) {
00074                 fixed = ISC_TRUE;
00075                 do {
00076                         tv->tv_sec += 1;
00077                         tv->tv_usec -= US_PER_S;
00078                 } while (tv->tv_usec >=US_PER_S);
00079         }
00080         /*
00081          * Call syslog directly as was are called from the logging functions.
00082          */
00083         if (fixed)
00084                 (void)syslog(LOG_ERR, "gettimeofday returned bad tv_usec: corrected");
00085 }
00086 #endif
00087 
00088 void
00089 isc_interval_set(isc_interval_t *i,
00090                  unsigned int seconds, unsigned int nanoseconds)
00091 {
00092         REQUIRE(i != NULL);
00093         REQUIRE(nanoseconds < NS_PER_S);
00094 
00095         i->seconds = seconds;
00096         i->nanoseconds = nanoseconds;
00097 }
00098 
00099 isc_boolean_t
00100 isc_interval_iszero(const isc_interval_t *i) {
00101         REQUIRE(i != NULL);
00102         INSIST(i->nanoseconds < NS_PER_S);
00103 
00104         if (i->seconds == 0 && i->nanoseconds == 0)
00105                 return (ISC_TRUE);
00106 
00107         return (ISC_FALSE);
00108 }
00109 
00110 
00111 /***
00112  *** Absolute Times
00113  ***/
00114 
00115 static const isc_time_t epoch = { 0, 0 };
00116 const isc_time_t * const isc_time_epoch = &epoch;
00117 
00118 void
00119 isc_time_set(isc_time_t *t, unsigned int seconds, unsigned int nanoseconds) {
00120         REQUIRE(t != NULL);
00121         REQUIRE(nanoseconds < NS_PER_S);
00122 
00123         t->seconds = seconds;
00124         t->nanoseconds = nanoseconds;
00125 }
00126 
00127 void
00128 isc_time_settoepoch(isc_time_t *t) {
00129         REQUIRE(t != NULL);
00130 
00131         t->seconds = 0;
00132         t->nanoseconds = 0;
00133 }
00134 
00135 isc_boolean_t
00136 isc_time_isepoch(const isc_time_t *t) {
00137         REQUIRE(t != NULL);
00138         INSIST(t->nanoseconds < NS_PER_S);
00139 
00140         if (t->seconds == 0 && t->nanoseconds == 0)
00141                 return (ISC_TRUE);
00142 
00143         return (ISC_FALSE);
00144 }
00145 
00146 
00147 isc_result_t
00148 isc_time_now(isc_time_t *t) {
00149         struct timeval tv;
00150         char strbuf[ISC_STRERRORSIZE];
00151 
00152         REQUIRE(t != NULL);
00153 
00154         if (gettimeofday(&tv, NULL) == -1) {
00155                 isc__strerror(errno, strbuf, sizeof(strbuf));
00156                 UNEXPECTED_ERROR(__FILE__, __LINE__, "%s", strbuf);
00157                 return (ISC_R_UNEXPECTED);
00158         }
00159 
00160         /*
00161          * Does POSIX guarantee the signedness of tv_sec and tv_usec?  If not,
00162          * then this test will generate warnings for platforms on which it is
00163          * unsigned.  In any event, the chances of any of these problems
00164          * happening are pretty much zero, but since the libisc library ensures
00165          * certain things to be true ...
00166          */
00167 #if ISC_FIX_TV_USEC
00168         fix_tv_usec(&tv);
00169         if (tv.tv_sec < 0)
00170                 return (ISC_R_UNEXPECTED);
00171 #else
00172         if (tv.tv_sec < 0 || tv.tv_usec < 0 || tv.tv_usec >= US_PER_S)
00173                 return (ISC_R_UNEXPECTED);
00174 #endif
00175 
00176         /*
00177          * Ensure the tv_sec value fits in t->seconds.
00178          */
00179         if (sizeof(tv.tv_sec) > sizeof(t->seconds) &&
00180             ((tv.tv_sec | (unsigned int)-1) ^ (unsigned int)-1) != 0U)
00181                 return (ISC_R_RANGE);
00182 
00183         t->seconds = tv.tv_sec;
00184         t->nanoseconds = tv.tv_usec * NS_PER_US;
00185 
00186         return (ISC_R_SUCCESS);
00187 }
00188 
00189 isc_result_t
00190 isc_time_nowplusinterval(isc_time_t *t, const isc_interval_t *i) {
00191         struct timeval tv;
00192         char strbuf[ISC_STRERRORSIZE];
00193 
00194         REQUIRE(t != NULL);
00195         REQUIRE(i != NULL);
00196         INSIST(i->nanoseconds < NS_PER_S);
00197 
00198         if (gettimeofday(&tv, NULL) == -1) {
00199                 isc__strerror(errno, strbuf, sizeof(strbuf));
00200                 UNEXPECTED_ERROR(__FILE__, __LINE__, "%s", strbuf);
00201                 return (ISC_R_UNEXPECTED);
00202         }
00203 
00204         /*
00205          * Does POSIX guarantee the signedness of tv_sec and tv_usec?  If not,
00206          * then this test will generate warnings for platforms on which it is
00207          * unsigned.  In any event, the chances of any of these problems
00208          * happening are pretty much zero, but since the libisc library ensures
00209          * certain things to be true ...
00210          */
00211 #if ISC_FIX_TV_USEC
00212         fix_tv_usec(&tv);
00213         if (tv.tv_sec < 0)
00214                 return (ISC_R_UNEXPECTED);
00215 #else
00216         if (tv.tv_sec < 0 || tv.tv_usec < 0 || tv.tv_usec >= US_PER_S)
00217                 return (ISC_R_UNEXPECTED);
00218 #endif
00219 
00220         /*
00221          * Ensure the resulting seconds value fits in the size of an
00222          * unsigned int.  (It is written this way as a slight optimization;
00223          * note that even if both values == INT_MAX, then when added
00224          * and getting another 1 added below the result is UINT_MAX.)
00225          */
00226         if ((tv.tv_sec > INT_MAX || i->seconds > INT_MAX) &&
00227             ((long long)tv.tv_sec + i->seconds > UINT_MAX))
00228                 return (ISC_R_RANGE);
00229 
00230         t->seconds = tv.tv_sec + i->seconds;
00231         t->nanoseconds = tv.tv_usec * NS_PER_US + i->nanoseconds;
00232         if (t->nanoseconds >= NS_PER_S) {
00233                 t->seconds++;
00234                 t->nanoseconds -= NS_PER_S;
00235         }
00236 
00237         return (ISC_R_SUCCESS);
00238 }
00239 
00240 int
00241 isc_time_compare(const isc_time_t *t1, const isc_time_t *t2) {
00242         REQUIRE(t1 != NULL && t2 != NULL);
00243         INSIST(t1->nanoseconds < NS_PER_S && t2->nanoseconds < NS_PER_S);
00244 
00245         if (t1->seconds < t2->seconds)
00246                 return (-1);
00247         if (t1->seconds > t2->seconds)
00248                 return (1);
00249         if (t1->nanoseconds < t2->nanoseconds)
00250                 return (-1);
00251         if (t1->nanoseconds > t2->nanoseconds)
00252                 return (1);
00253         return (0);
00254 }
00255 
00256 isc_result_t
00257 isc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result)
00258 {
00259         REQUIRE(t != NULL && i != NULL && result != NULL);
00260         INSIST(t->nanoseconds < NS_PER_S && i->nanoseconds < NS_PER_S);
00261 
00262         /*
00263          * Ensure the resulting seconds value fits in the size of an
00264          * unsigned int.  (It is written this way as a slight optimization;
00265          * note that even if both values == INT_MAX, then when added
00266          * and getting another 1 added below the result is UINT_MAX.)
00267          */
00268         if ((t->seconds > INT_MAX || i->seconds > INT_MAX) &&
00269             ((long long)t->seconds + i->seconds > UINT_MAX))
00270                 return (ISC_R_RANGE);
00271 
00272         result->seconds = t->seconds + i->seconds;
00273         result->nanoseconds = t->nanoseconds + i->nanoseconds;
00274         if (result->nanoseconds >= NS_PER_S) {
00275                 result->seconds++;
00276                 result->nanoseconds -= NS_PER_S;
00277         }
00278 
00279         return (ISC_R_SUCCESS);
00280 }
00281 
00282 isc_result_t
00283 isc_time_subtract(const isc_time_t *t, const isc_interval_t *i,
00284                   isc_time_t *result)
00285 {
00286         REQUIRE(t != NULL && i != NULL && result != NULL);
00287         INSIST(t->nanoseconds < NS_PER_S && i->nanoseconds < NS_PER_S);
00288 
00289         if ((unsigned int)t->seconds < i->seconds ||
00290             ((unsigned int)t->seconds == i->seconds &&
00291              t->nanoseconds < i->nanoseconds))
00292             return (ISC_R_RANGE);
00293 
00294         result->seconds = t->seconds - i->seconds;
00295         if (t->nanoseconds >= i->nanoseconds)
00296                 result->nanoseconds = t->nanoseconds - i->nanoseconds;
00297         else {
00298                 result->nanoseconds = NS_PER_S - i->nanoseconds +
00299                         t->nanoseconds;
00300                 result->seconds--;
00301         }
00302 
00303         return (ISC_R_SUCCESS);
00304 }
00305 
00306 isc_uint64_t
00307 isc_time_microdiff(const isc_time_t *t1, const isc_time_t *t2) {
00308         isc_uint64_t i1, i2, i3;
00309 
00310         REQUIRE(t1 != NULL && t2 != NULL);
00311         INSIST(t1->nanoseconds < NS_PER_S && t2->nanoseconds < NS_PER_S);
00312 
00313         i1 = (isc_uint64_t)t1->seconds * NS_PER_S + t1->nanoseconds;
00314         i2 = (isc_uint64_t)t2->seconds * NS_PER_S + t2->nanoseconds;
00315 
00316         if (i1 <= i2)
00317                 return (0);
00318 
00319         i3 = i1 - i2;
00320 
00321         /*
00322          * Convert to microseconds.
00323          */
00324         i3 /= NS_PER_US;
00325 
00326         return (i3);
00327 }
00328 
00329 isc_uint32_t
00330 isc_time_seconds(const isc_time_t *t) {
00331         REQUIRE(t != NULL);
00332         INSIST(t->nanoseconds < NS_PER_S);
00333 
00334         return ((isc_uint32_t)t->seconds);
00335 }
00336 
00337 isc_result_t
00338 isc_time_secondsastimet(const isc_time_t *t, time_t *secondsp) {
00339         time_t seconds;
00340 
00341         REQUIRE(t != NULL);
00342         INSIST(t->nanoseconds < NS_PER_S);
00343 
00344         /*
00345          * Ensure that the number of seconds represented by t->seconds
00346          * can be represented by a time_t.  Since t->seconds is an unsigned
00347          * int and since time_t is mostly opaque, this is trickier than
00348          * it seems.  (This standardized opaqueness of time_t is *very*
00349          * frustrating; time_t is not even limited to being an integral
00350          * type.)
00351          *
00352          * The mission, then, is to avoid generating any kind of warning
00353          * about "signed versus unsigned" while trying to determine if the
00354          * the unsigned int t->seconds is out range for tv_sec, which is
00355          * pretty much only true if time_t is a signed integer of the same
00356          * size as the return value of isc_time_seconds.
00357          *
00358          * If the paradox in the if clause below is true, t->seconds is out
00359          * of range for time_t.
00360          */
00361         seconds = (time_t)t->seconds;
00362 
00363         INSIST(sizeof(unsigned int) == sizeof(isc_uint32_t));
00364         INSIST(sizeof(time_t) >= sizeof(isc_uint32_t));
00365 
00366         if (t->seconds > (~0U>>1) && seconds <= (time_t)(~0U>>1))
00367                 return (ISC_R_RANGE);
00368 
00369         *secondsp = seconds;
00370 
00371         return (ISC_R_SUCCESS);
00372 }
00373 
00374 isc_uint32_t
00375 isc_time_nanoseconds(const isc_time_t *t) {
00376         REQUIRE(t != NULL);
00377 
00378         ENSURE(t->nanoseconds < NS_PER_S);
00379 
00380         return ((isc_uint32_t)t->nanoseconds);
00381 }
00382 
00383 void
00384 isc_time_formattimestamp(const isc_time_t *t, char *buf, unsigned int len) {
00385         time_t now;
00386         unsigned int flen;
00387 
00388         REQUIRE(len > 0);
00389 
00390         now = (time_t) t->seconds;
00391         flen = strftime(buf, len, "%d-%b-%Y %X", localtime(&now));
00392         INSIST(flen < len);
00393         if (flen != 0)
00394                 snprintf(buf + flen, len - flen,
00395                          ".%03u", t->nanoseconds / 1000000);
00396         else {
00397                 strncpy(buf, "99-Bad-9999 99:99:99.999", len);
00398                 buf[len - 1] = 0;
00399         }
00400 }
00401 
00402 void
00403 isc_time_formathttptimestamp(const isc_time_t *t, char *buf, unsigned int len) {
00404         time_t now;
00405         unsigned int flen;
00406 
00407         REQUIRE(len > 0);
00408 
00409         /*
00410          * 5 spaces, 1 comma, 3 GMT, 2 %d, 4 %Y, 8 %H:%M:%S, 3+ %a, 3+ %b (29+)
00411          */
00412         now = (time_t)t->seconds;
00413         flen = strftime(buf, len, "%a, %d %b %Y %H:%M:%S GMT", gmtime(&now));
00414         INSIST(flen < len);
00415 }
00416 
00417 isc_result_t
00418 isc_time_parsehttptimestamp(char *buf, isc_time_t *t) {
00419         struct tm t_tm;
00420         time_t when;
00421         char *p;
00422 
00423         REQUIRE(buf != NULL);
00424         REQUIRE(t != NULL);
00425         p = isc_tm_strptime(buf, "%a, %d %b %Y %H:%M:%S", &t_tm);
00426         if (p == NULL)
00427                 return (ISC_R_UNEXPECTED);
00428         when = isc_tm_timegm(&t_tm);
00429         if (when == -1)
00430                 return (ISC_R_UNEXPECTED);
00431         isc_time_set(t, when, 0);
00432         return (ISC_R_SUCCESS);
00433 }
00434 
00435 void
00436 isc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len) {
00437         time_t now;
00438         unsigned int flen;
00439 
00440         REQUIRE(len > 0);
00441 
00442         now = (time_t)t->seconds;
00443         flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%SZ", gmtime(&now));
00444         INSIST(flen < len);
00445 }

Generated on Tue Apr 28 17:41:06 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha