nwrap: Fix resolving hostnames with a trailing dot.
[sfrench/samba-autobuild/.git] / lib / util / time.c
index 978d73cc0a1731319ef61a96b239dcfcf678cc93..4b78e71a789fd2131beb6bae0483e05e9122e13d 100644 (file)
@@ -4,6 +4,8 @@
 
    Copyright (C) Andrew Tridgell               1992-2004
    Copyright (C) Stefan (metze) Metzmacher     2002   
+   Copyright (C) Jeremy Allison                        2007
+   Copyright (C) Andrew Bartlett                2011
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
+#include "replace.h"
 #include "system/time.h"
+#include "byteorder.h"
+#include "time_basic.h"
+#include "lib/util/time.h" /* Avoid /usr/include/time.h */
 
 /**
  * @file
  * @brief time handling functions
  */
 
-#ifndef TIME_T_MIN
-/* we use 0 here, because (time_t)-1 means error */
-#define TIME_T_MIN 0
+#if (SIZEOF_LONG == 8)
+#define TIME_FIXUP_CONSTANT_INT 11644473600L
+#elif (SIZEOF_LONG_LONG == 8)
+#define TIME_FIXUP_CONSTANT_INT 11644473600LL
 #endif
 
-/*
- * we use the INT32_MAX here as on 64 bit systems,
- * gmtime() fails with INT64_MAX
- */
 
-#ifndef TIME_T_MAX
-#define TIME_T_MAX MIN(INT32_MAX,_TYPE_MAXIMUM(time_t))
-#endif
 
 /**
  External access to time_t_min and time_t_max.
@@ -50,41 +49,83 @@ _PUBLIC_ time_t get_time_t_max(void)
 }
 
 /**
-a gettimeofday wrapper
+a wrapper to preferably get the monotonic time
 **/
-_PUBLIC_ void GetTimeOfDay(struct timeval *tval)
+_PUBLIC_ void clock_gettime_mono(struct timespec *tp)
 {
-#ifdef HAVE_GETTIMEOFDAY_TZ
-       gettimeofday(tval,NULL);
-#else
-       gettimeofday(tval);
+/* prefer a suspend aware monotonic CLOCK_BOOTTIME: */
+#ifdef CLOCK_BOOTTIME
+       if (clock_gettime(CLOCK_BOOTTIME,tp) == 0) {
+               return;
+       }
 #endif
+/* then try the  monotonic clock: */
+#if CUSTOM_CLOCK_MONOTONIC != CLOCK_REALTIME
+       if (clock_gettime(CUSTOM_CLOCK_MONOTONIC,tp) == 0) {
+               return;
+       }
+#endif
+       clock_gettime(CLOCK_REALTIME,tp);
 }
 
-
-#define TIME_FIXUP_CONSTANT 11644473600LL
-
 /**
-interpret an 8 byte "filetime" structure to a time_t
-It's originally in "100ns units since jan 1st 1601"
+a wrapper to preferably get the monotonic time in seconds
 **/
-_PUBLIC_ time_t nt_time_to_unix(NTTIME nt)
+_PUBLIC_ time_t time_mono(time_t *t)
 {
-       if (nt == 0) {
-               return 0;
+       struct timespec tp;
+
+       clock_gettime_mono(&tp);
+       if (t != NULL) {
+               *t = tp.tv_sec;
        }
-       if (nt == -1LL) {
-               return (time_t)-1;
+       return tp.tv_sec;
+}
+
+
+#define TIME_FIXUP_CONSTANT 11644473600LL
+
+time_t convert_timespec_to_time_t(struct timespec ts)
+{
+       /* Ensure tv_nsec is less than 1sec. */
+       while (ts.tv_nsec > 1000000000) {
+               ts.tv_sec += 1;
+               ts.tv_nsec -= 1000000000;
        }
-       nt += 1000*1000*10/2;
-       nt /= 1000*1000*10;
-       nt -= TIME_FIXUP_CONSTANT;
 
-       if (TIME_T_MIN > nt || nt > TIME_T_MAX) {
-               return 0;
+       /* 1 ns == 1,000,000,000 - one thousand millionths of a second.
+          increment if it's greater than 500 millionth of a second. */
+
+       if (ts.tv_nsec > 500000000) {
+               return ts.tv_sec + 1;
        }
+       return ts.tv_sec;
+}
 
-       return (time_t)nt;
+struct timespec convert_time_t_to_timespec(time_t t)
+{
+       struct timespec ts;
+       ts.tv_sec = t;
+       ts.tv_nsec = 0;
+       return ts;
+}
+
+
+
+/**
+ Interpret an 8 byte "filetime" structure to a time_t
+ It's originally in "100ns units since jan 1st 1601"
+
+ An 8 byte value of 0xffffffffffffffff will be returned as a timespec of
+
+       tv_sec = 0
+       tv_nsec = 0;
+
+ Returns GMT.
+**/
+time_t nt_time_to_unix(NTTIME nt)
+{
+       return convert_timespec_to_time_t(nt_time_to_unix_timespec(nt));
 }
 
 
@@ -99,14 +140,20 @@ _PUBLIC_ void unix_to_nt_time(NTTIME *nt, time_t t)
        if (t == (time_t)-1) {
                *nt = (NTTIME)-1LL;
                return;
-       }               
+       }       
+
+       if (t == TIME_T_MAX || t == INT64_MAX) {
+               *nt = 0x7fffffffffffffffLL;
+               return;
+       }
+
        if (t == 0) {
                *nt = 0;
                return;
        }               
 
        t2 = t;
-       t2 += TIME_FIXUP_CONSTANT;
+       t2 += TIME_FIXUP_CONSTANT_INT;
        t2 *= 1000*1000*10;
 
        *nt = t2;
@@ -218,7 +265,7 @@ _PUBLIC_ void push_dos_date3(uint8_t *buf,int offset,time_t unixdate, int zone_o
 /*******************************************************************
   interpret a 32 bit dos packed date/time to some parameters
 ********************************************************************/
-static void interpret_dos_date(uint32_t date,int *year,int *month,int *day,int *hour,int *minute,int *second)
+void interpret_dos_date(uint32_t date,int *year,int *month,int *day,int *hour,int *minute,int *second)
 {
        uint32_t p0,p1,p2,p3;
 
@@ -285,6 +332,41 @@ _PUBLIC_ time_t pull_dos_date3(const uint8_t *date_ptr, int zone_offset)
        return t;
 }
 
+/****************************************************************************
+ Return the date and time as a string
+****************************************************************************/
+
+char *timeval_string(TALLOC_CTX *ctx, const struct timeval *tp, bool hires)
+{
+       struct timeval_buf tmp;
+       char *result;
+
+       result = talloc_strdup(ctx, timeval_str_buf(tp, hires, &tmp));
+       if (result == NULL) {
+               return NULL;
+       }
+
+       /*
+        * beautify the talloc_report output
+        *
+        * This is not just cosmetics. A C compiler might in theory make the
+        * talloc_strdup call above a tail call with the tail call
+        * optimization. This would render "tmp" invalid while talloc_strdup
+        * tries to duplicate it. The talloc_set_name_const call below puts
+        * the talloc_strdup call into non-tail position.
+        */
+       talloc_set_name_const(result, result);
+       return result;
+}
+
+char *current_timestring(TALLOC_CTX *ctx, bool hires)
+{
+       struct timeval tv;
+
+       GetTimeOfDay(&tv);
+       return timeval_string(ctx, &tv, hires);
+}
+
 
 /**
 return a HTTP/1.0 time string
@@ -295,6 +377,10 @@ _PUBLIC_ char *http_timestring(TALLOC_CTX *mem_ctx, time_t t)
        char tempTime[60];
        struct tm *tm = localtime(&t);
 
+       if (t == TIME_T_MAX) {
+               return talloc_strdup(mem_ctx, "never");
+       }
+
        if (!tm) {
                return talloc_asprintf(mem_ctx,"%ld seconds since the Epoch",(long)t);
        }
@@ -329,14 +415,22 @@ _PUBLIC_ char *timestring(TALLOC_CTX *mem_ctx, time_t t)
        }
 
 #ifdef HAVE_STRFTIME
-       /* some versions of gcc complain about using %c. This is a bug
-          in the gcc warning, not a bug in this code. See a recent
-          strftime() manual page for details.
-        */
-       strftime(tempTime,sizeof(tempTime)-1,"%c %Z",tm);
+       /* Some versions of gcc complain about using some special format
+        * specifiers. This is a bug in gcc, not a bug in this code. See a
+        * recent strftime() manual page for details. */
+       strftime(tempTime,sizeof(tempTime)-1,"%a %b %e %X %Y %Z",tm);
        TimeBuf = talloc_strdup(mem_ctx, tempTime);
 #else
        TimeBuf = talloc_strdup(mem_ctx, asctime(tm));
+       if (TimeBuf == NULL) {
+               return NULL;
+       }
+       if (TimeBuf[0] != '\0') {
+               size_t len = strlen(TimeBuf);
+               if (TimeBuf[len - 1] == '\n') {
+                       TimeBuf[len - 1] = '\0';
+               }
+       }
 #endif
 
        return TimeBuf;
@@ -382,6 +476,15 @@ _PUBLIC_ int64_t usec_time_diff(const struct timeval *tv1, const struct timeval
        return (sec_diff * 1000000) + (int64_t)(tv1->tv_usec - tv2->tv_usec);
 }
 
+/**
+  return (tp1 - tp2) in microseconds
+*/
+_PUBLIC_ int64_t nsec_time_diff(const struct timespec *tp1, const struct timespec *tp2)
+{
+       int64_t sec_diff = tp1->tv_sec - tp2->tv_sec;
+       return (sec_diff * 1000000000) + (int64_t)(tp1->tv_nsec - tp2->tv_nsec);
+}
+
 
 /**
   return a zero timeval
@@ -457,6 +560,24 @@ _PUBLIC_ struct timeval timeval_current_ofs(uint32_t secs, uint32_t usecs)
        return timeval_add(&tv, secs, usecs);
 }
 
+/**
+  return a timeval milliseconds into the future
+*/
+_PUBLIC_ struct timeval timeval_current_ofs_msec(uint32_t msecs)
+{
+       struct timeval tv = timeval_current();
+       return timeval_add(&tv, msecs / 1000, (msecs % 1000) * 1000);
+}
+
+/**
+  return a timeval microseconds into the future
+*/
+_PUBLIC_ struct timeval timeval_current_ofs_usec(uint32_t usecs)
+{
+       struct timeval tv = timeval_current();
+       return timeval_add(&tv, usecs / 1000000, usecs % 1000000);
+}
+
 /**
   compare two timeval structures. 
   Return -1 if tv1 < tv2
@@ -500,6 +621,24 @@ _PUBLIC_ double timeval_elapsed(const struct timeval *tv)
        struct timeval tv2 = timeval_current();
        return timeval_elapsed2(tv, &tv2);
 }
+/**
+ *   return the number of seconds elapsed between two times
+ **/
+_PUBLIC_ double timespec_elapsed2(const struct timespec *ts1,
+                               const struct timespec *ts2)
+{
+       return (ts2->tv_sec - ts1->tv_sec) +
+              (ts2->tv_nsec - ts1->tv_nsec)*1.0e-9;
+}
+
+/**
+ *   return the number of seconds elapsed since a given time
+ */
+_PUBLIC_ double timespec_elapsed(const struct timespec *ts)
+{
+       struct timespec ts2 = timespec_current();
+       return timespec_elapsed2(ts, &ts2);
+}
 
 /**
   return the lesser of two timevals
@@ -597,6 +736,7 @@ static int tm_diff(struct tm *a, struct tm *b)
        return seconds;
 }
 
+
 /**
   return the UTC offset in seconds west of UTC, or 0 if it cannot be determined
  */
@@ -613,6 +753,50 @@ _PUBLIC_ int get_time_zone(time_t t)
        return tm_diff(&tm_utc,tm);
 }
 
+struct timespec nt_time_to_unix_timespec(NTTIME nt)
+{
+       int64_t d;
+       struct timespec ret;
+
+       if (nt == 0 || nt == (int64_t)-1) {
+               ret.tv_sec = 0;
+               ret.tv_nsec = 0;
+               return ret;
+       }
+
+       d = (int64_t)nt;
+       /* d is now in 100ns units, since jan 1st 1601".
+          Save off the ns fraction. */
+
+       /*
+        * Take the last seven decimal digits and multiply by 100.
+        * to convert from 100ns units to 1ns units.
+        */
+        ret.tv_nsec = (long) ((d % (1000 * 1000 * 10)) * 100);
+
+       /* Convert to seconds */
+       d /= 1000*1000*10;
+
+       /* Now adjust by 369 years to make the secs since 1970 */
+       d -= TIME_FIXUP_CONSTANT_INT;
+
+       if (d <= (int64_t)TIME_T_MIN) {
+               ret.tv_sec = TIME_T_MIN;
+               ret.tv_nsec = 0;
+               return ret;
+       }
+
+       if (d >= (int64_t)TIME_T_MAX) {
+               ret.tv_sec = TIME_T_MAX;
+               ret.tv_nsec = 0;
+               return ret;
+       }
+
+       ret.tv_sec = (time_t)d;
+       return ret;
+}
+
+
 /**
   check if 2 NTTIMEs are equal.
 */
@@ -620,3 +804,130 @@ bool nt_time_equal(NTTIME *t1, NTTIME *t2)
 {
        return *t1 == *t2;
 }
+
+/**
+ Check if it's a null timespec.
+**/
+
+bool null_timespec(struct timespec ts)
+{
+       return ts.tv_sec == 0 || 
+               ts.tv_sec == (time_t)0xFFFFFFFF || 
+               ts.tv_sec == (time_t)-1;
+}
+
+/****************************************************************************
+ Convert a normalized timeval to a timespec.
+****************************************************************************/
+
+struct timespec convert_timeval_to_timespec(const struct timeval tv)
+{
+       struct timespec ts;
+       ts.tv_sec = tv.tv_sec;
+       ts.tv_nsec = tv.tv_usec * 1000;
+       return ts;
+}
+
+/****************************************************************************
+ Convert a normalized timespec to a timeval.
+****************************************************************************/
+
+struct timeval convert_timespec_to_timeval(const struct timespec ts)
+{
+       struct timeval tv;
+       tv.tv_sec = ts.tv_sec;
+       tv.tv_usec = ts.tv_nsec / 1000;
+       return tv;
+}
+
+/****************************************************************************
+ Return a timespec for the current time
+****************************************************************************/
+
+_PUBLIC_ struct timespec timespec_current(void)
+{
+       struct timespec ts;
+       clock_gettime(CLOCK_REALTIME, &ts);
+       return ts;
+}
+
+/****************************************************************************
+ Return the lesser of two timespecs.
+****************************************************************************/
+
+struct timespec timespec_min(const struct timespec *ts1,
+                          const struct timespec *ts2)
+{
+       if (ts1->tv_sec < ts2->tv_sec) return *ts1;
+       if (ts1->tv_sec > ts2->tv_sec) return *ts2;
+       if (ts1->tv_nsec < ts2->tv_nsec) return *ts1;
+       return *ts2;
+}
+
+/****************************************************************************
+  compare two timespec structures. 
+  Return -1 if ts1 < ts2
+  Return 0 if ts1 == ts2
+  Return 1 if ts1 > ts2
+****************************************************************************/
+
+_PUBLIC_ int timespec_compare(const struct timespec *ts1, const struct timespec *ts2)
+{
+       if (ts1->tv_sec  > ts2->tv_sec)  return 1;
+       if (ts1->tv_sec  < ts2->tv_sec)  return -1;
+       if (ts1->tv_nsec > ts2->tv_nsec) return 1;
+       if (ts1->tv_nsec < ts2->tv_nsec) return -1;
+       return 0;
+}
+
+/****************************************************************************
+ Round up a timespec if nsec > 500000000, round down if lower,
+ then zero nsec.
+****************************************************************************/
+
+void round_timespec_to_sec(struct timespec *ts)
+{
+       ts->tv_sec = convert_timespec_to_time_t(*ts);
+       ts->tv_nsec = 0;
+}
+
+/****************************************************************************
+ Round a timespec to usec value.
+****************************************************************************/
+
+void round_timespec_to_usec(struct timespec *ts)
+{
+       struct timeval tv = convert_timespec_to_timeval(*ts);
+       *ts = convert_timeval_to_timespec(tv);
+       while (ts->tv_nsec > 1000000000) {
+               ts->tv_sec += 1;
+               ts->tv_nsec -= 1000000000;
+       }
+}
+
+/****************************************************************************
+ Put a 8 byte filetime from a struct timespec. Uses GMT.
+****************************************************************************/
+
+_PUBLIC_ NTTIME unix_timespec_to_nt_time(struct timespec ts)
+{
+       uint64_t d;
+
+       if (ts.tv_sec ==0 && ts.tv_nsec == 0) {
+               return 0;
+       }
+       if (ts.tv_sec == TIME_T_MAX) {
+               return 0x7fffffffffffffffLL;
+       }
+       if (ts.tv_sec == (time_t)-1) {
+               return (uint64_t)-1;
+       }
+
+       d = ts.tv_sec;
+       d += TIME_FIXUP_CONSTANT_INT;
+       d *= 1000*1000*10;
+       /* d is now in 100ns units. */
+       d += (ts.tv_nsec / 100);
+
+       return d;
+}