]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Add generic time scaling functions
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Thu, 28 Oct 2021 16:32:07 +0000 (12:32 -0400)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Thu, 28 Oct 2021 16:38:38 +0000 (12:38 -0400)
Deal with integer overflow in time manipulation and scaling functions by returning min/max.

src/lib/util/time.c
src/lib/util/time.h
src/lib/util/value.c
src/modules/rlm_expr/rlm_expr.c

index bec951f7c4af5b9bcb7242452b3ec4220cc2c27a..aeb5377d1f57a18206c50b2f938a9dc92c0acfa5 100644 (file)
@@ -656,31 +656,6 @@ fr_unix_time_t fr_unix_time_from_tm(struct tm *tm)
        return fr_unix_time_from_sec((days - 2472692) * 86400 + (tm->tm_hour * 3600) + (tm->tm_min * 60) + tm->tm_sec + tm->tm_gmtoff);
 }
 
-int64_t fr_time_delta_scale(fr_time_delta_t delta, fr_time_res_t hint)
-{
-       switch (hint) {
-       case FR_TIME_RES_SEC:
-               return fr_time_delta_to_sec(delta);
-
-       case FR_TIME_RES_CSEC:
-               return fr_time_delta_to_csec(delta);
-
-       case FR_TIME_RES_MSEC:
-               return fr_time_delta_to_msec(delta);
-
-       case FR_TIME_RES_USEC:
-               return fr_time_delta_to_usec(delta);
-
-       case FR_TIME_RES_NSEC:
-               return fr_time_delta_unwrap(delta);
-
-       default:
-               break;
-       }
-
-       return 0;
-}
-
 /** Scale an input time to NSEC, clamping it at max / min.
  *
  * @param t    input time / time delta
index 5308e61de6ff9179841957af8d813a356aafb83a..f187ca84bd6274a7a6c38a2a5d1e269cd55a76ca 100644 (file)
  */
 RCSIDH(time_h, "$Id$")
 
-/*
- *     For sys/time.h and time.h
- */
-#include <freeradius-devel/missing.h>
-#include <freeradius-devel/util/debug.h>
-#include <freeradius-devel/util/sbuff.h>
+#include <stdint.h>
 #include <inttypes.h>
 #include <stdatomic.h>
-#include <stdint.h>
 #include <stdio.h>
 #include <sys/time.h>
 
@@ -42,6 +36,20 @@ RCSIDH(time_h, "$Id$")
 extern "C" {
 #endif
 
+/** The base resolution for print parse operations
+ */
+typedef enum {
+       FR_TIME_RES_INVALID = -1,
+       FR_TIME_RES_SEC = 0,
+       FR_TIME_RES_MIN,
+       FR_TIME_RES_HOUR,
+       FR_TIME_RES_DAY,
+       FR_TIME_RES_CSEC,
+       FR_TIME_RES_MSEC,
+       FR_TIME_RES_USEC,
+       FR_TIME_RES_NSEC
+} fr_time_res_t;
+
 /** "server local" time.  This is the time in nanoseconds since the application started.
  *
  *  This time is our *private* view of time.  It should only be used
@@ -54,11 +62,6 @@ typedef struct fr_time_s {
                                ///< entries.
 } fr_time_t;
 
-#define fr_time_max() (fr_time_t){ .value = INT64_MAX }
-#define fr_time_min() (fr_time_t){ .value = INT64_MIN }
-#define fr_time_wrap(_time) (fr_time_t){ .value = (_time) }
-static inline int64_t fr_time_unwrap(fr_time_t time) { return time.value; }    /* func to stop mixing with fr_time_delta_t */
-
 /** A time delta, a difference in time measured in nanoseconds.
  *
  * This is easier to distinguish where server epoch time is being
@@ -68,11 +71,6 @@ typedef struct fr_time_delta_s {
        int64_t value;
 } fr_time_delta_t;
 
-#define fr_time_delta_max() (fr_time_delta_t){ .value = INT64_MAX }
-#define fr_time_delta_min() (fr_time_delta_t){ .value = INT64_MIN }
-#define fr_time_delta_wrap(_time) (fr_time_delta_t){ .value = (_time) }
-static inline int64_t fr_time_delta_unwrap(fr_time_delta_t time) { return time.value; }        /* func to stop mixing with fr_time_t */
-
 /** "Unix" time.  This is the time in nanoseconds since midnight January 1, 1970
  *
  *  Note that it is *unsigned*, as we don't use dates before 1970.  Having it
@@ -88,13 +86,70 @@ typedef struct fr_unix_time_s {
        uint64_t value;
 } fr_unix_time_t;
 
+#ifdef __cplusplus
+}
+#endif
+
+/*
+ *     For sys/time.h and time.h
+ */
+#include <freeradius-devel/missing.h>
+#include <freeradius-devel/util/debug.h>
+#include <freeradius-devel/util/sbuff.h>
+#include <freeradius-devel/util/misc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 extern int64_t const                   fr_time_multiplier_by_res[];
 extern fr_table_num_ordered_t const    fr_time_precision_table[];
 extern size_t                          fr_time_precision_table_len;
+
+static bool fr_time_op_ispos(bool a, bool op, bool b)
+{
+       return ((a == op) == b);
+}
+
+/** Determine, if an overflow has occurred, which direction it occurred in
+ *
+ * @param[in] _a       First operand.
+ * @param[in] _op      Operator, true if add or multiply, false if subtract.
+ * @param[in] _b       Second operand.
+ */
+#define fr_time_overflow_ispos(_a, _op, _b) \
+fr_time_op_ispos( \
+       _Generic(&(_a), \
+                fr_time_t *: (fr_time_unwrap(*((fr_time_t *)&(_a))) >= 0), \
+                fr_time_delta_t *: (fr_time_delta_unwrap(*((fr_time_delta_t *)&(_a))) >= 0), \
+                fr_unix_time_t *: true), \
+       _op, \
+       _Generic(&(_b), \
+                fr_time_t *: (fr_time_unwrap(*((fr_time_t *)&(_b))) >= 0), \
+                fr_time_delta_t *: (fr_time_delta_unwrap(*((fr_time_delta_t *)&(_b))) >= 0), \
+                fr_unix_time_t *: true)\
+       )
+
+#define fr_time_max() (fr_time_t){ .value = INT64_MAX }
+#define fr_time_min() (fr_time_t){ .value = INT64_MIN }
+#define fr_time_wrap(_time) (fr_time_t){ .value = (_time) }
+static inline int64_t fr_time_unwrap(fr_time_t time) { return time.value; }    /* func to stop mixing with fr_time_delta_t */
+#define fr_time_overflow_add(_a, _b) (fr_time_overflow_ispos(_a, true, _b) ? fr_time_max() : fr_time_min())
+#define fr_time_overflow_sub(_a, _b) (fr_time_overflow_ispos(_a, false, _b) ? fr_time_max() : fr_time_min())
+
+#define fr_time_delta_max() (fr_time_delta_t){ .value = INT64_MAX }
+#define fr_time_delta_min() (fr_time_delta_t){ .value = INT64_MIN }
+#define fr_time_delta_wrap(_time) (fr_time_delta_t){ .value = (_time) }
+static inline int64_t fr_time_delta_unwrap(fr_time_delta_t time) { return time.value; }        /* func to stop mixing with fr_time_t */
+#define fr_time_delta_overflow_add(_a, _b) (fr_time_overflow_ispos(_a, true, _b) ? fr_time_delta_max() : fr_time_delta_min())
+#define fr_time_delta_overflow_sub(_a, _b) (fr_time_overflow_ispos(_a, false, _b) ? fr_time_delta_max() : fr_time_delta_min())
+
 #define fr_unix_time_max() (fr_unix_time_t){ .value = UINT64_MAX }
 #define fr_unix_time_min() (fr_unix_time_t){ .value = 0 }
 #define fr_unix_time_wrap(_time) (fr_unix_time_t){ .value = (_time) }
 static inline uint64_t fr_unix_time_unwrap(fr_unix_time_t time) { return time.value; } /* func to stop mixing with fr_time_t */
+#define fr_unix_time_overflow_add(_a, _b) (fr_time_overflow_ispos(_a, true, _b) ? fr_unix_time_max() : fr_unix_time_min())
+#define fr_unix_time_overflow_sub(_a, _b) (fr_time_overflow_ispos(_a, false, _b) ? fr_unix_time_max() : fr_unix_time_min())
 
 /** @name fr_time_t arithmetic and comparison macros
  *
@@ -104,8 +159,19 @@ static inline uint64_t fr_unix_time_unwrap(fr_unix_time_t time) { return time.va
  * @{
  */
 /* Don't add fr_time_add_time_time, it's almost always a type error */
-static inline fr_time_t fr_time_add_time_delta(fr_time_t a, fr_time_delta_t b) { return fr_time_wrap(fr_time_unwrap(a) + fr_time_delta_unwrap(b)); }
-static inline fr_time_t fr_time_add_delta_time(fr_time_delta_t a, fr_time_t b) { return fr_time_wrap(fr_time_delta_unwrap(a) + fr_time_unwrap(b)); }
+static inline fr_time_t fr_time_add_time_delta(fr_time_t a, fr_time_delta_t b)
+{
+       typeof_field(fr_time_t, value) out;
+       if (!fr_add(&out, fr_time_unwrap(a), fr_time_delta_unwrap(b))) return fr_time_overflow_add(a, b);
+       return fr_time_wrap(out);
+}
+
+static inline fr_time_t fr_time_add_delta_time(fr_time_delta_t a, fr_time_t b)
+{
+       typeof_field(fr_time_t, value) out;
+       if (!fr_add(&out, fr_time_delta_unwrap(a), fr_time_unwrap(b))) return fr_time_overflow_add(a, b);
+       return fr_time_wrap(out);
+}
 
 /** Add a time/time delta together
  *
@@ -127,8 +193,18 @@ static inline fr_time_t fr_time_add_delta_time(fr_time_delta_t a, fr_time_t b) {
                                  ) \
        )(_a, _b)
 
-static inline fr_time_delta_t fr_time_sub_time_time(fr_time_t a, fr_time_t b) { return fr_time_delta_wrap(fr_time_unwrap(a) - fr_time_unwrap(b)); }
-static inline fr_time_t fr_time_sub_time_delta(fr_time_t a, fr_time_delta_t b) { return fr_time_wrap(fr_time_unwrap(a) - fr_time_delta_unwrap(b)); }
+static inline fr_time_delta_t fr_time_sub_time_time(fr_time_t a, fr_time_t b)
+{
+       typeof_field(fr_time_t, value) out;
+       if (!fr_sub(&out, fr_time_unwrap(a), fr_time_unwrap(b))) return fr_time_delta_overflow_sub(a, b);
+       return fr_time_delta_wrap(out);
+}
+static inline fr_time_t fr_time_sub_time_delta(fr_time_t a, fr_time_delta_t b)
+{
+       typeof_field(fr_time_t, value) out;
+       if (!fr_sub(&out, fr_time_unwrap(a), fr_time_delta_unwrap(b))) return fr_time_overflow_sub(a, b);
+       return fr_time_wrap(out);
+}
 
 /** Subtract one time from another
  *
@@ -165,10 +241,30 @@ static inline fr_time_t fr_time_sub_time_delta(fr_time_t a, fr_time_delta_t b) {
  * The macros below allow basic arithmetic and comparisons to be performed.
  * @{
  */
-static inline fr_time_delta_t fr_time_delta_add(fr_time_delta_t a, fr_time_delta_t b) { return fr_time_delta_wrap(fr_time_delta_unwrap(a) + fr_time_delta_unwrap(b)); }
-static inline fr_time_delta_t fr_time_delta_sub(fr_time_delta_t a, fr_time_delta_t b) { return fr_time_delta_wrap(fr_time_delta_unwrap(a) - fr_time_delta_unwrap(b)); }
-static inline fr_time_delta_t fr_time_delta_div(fr_time_delta_t a, fr_time_delta_t b) { return fr_time_delta_wrap(fr_time_delta_unwrap(a) / fr_time_delta_unwrap(b)); }
-static inline fr_time_delta_t fr_time_delta_mul(fr_time_delta_t a, fr_time_delta_t b) { return fr_time_delta_wrap(fr_time_delta_unwrap(a) * fr_time_delta_unwrap(b)); }
+static inline fr_time_delta_t fr_time_delta_add(fr_time_delta_t a, fr_time_delta_t b)
+{
+       typeof_field(fr_time_delta_t, value) out;
+       if (!fr_add(&out, fr_time_delta_unwrap(a), fr_time_delta_unwrap(b))) return fr_time_delta_overflow_add(a, b);
+       return fr_time_delta_wrap(out);
+}
+static inline fr_time_delta_t fr_time_delta_sub(fr_time_delta_t a, fr_time_delta_t b)
+{
+       typeof_field(fr_time_delta_t, value) out;
+       if (!fr_sub(&out, fr_time_delta_unwrap(a), fr_time_delta_unwrap(b))) return fr_time_delta_overflow_sub(a, b);
+       return fr_time_delta_wrap(out);
+}
+static inline fr_time_delta_t fr_time_delta_div(fr_time_delta_t a, fr_time_delta_t b)
+{
+       return fr_time_delta_wrap(fr_time_delta_unwrap(a) / fr_time_delta_unwrap(b));
+}
+static inline fr_time_delta_t fr_time_delta_mul(fr_time_delta_t a, fr_time_delta_t b)
+{
+       typeof_field(fr_time_delta_t, value) out;
+       if (!fr_multiply(&out, fr_time_delta_unwrap(a), fr_time_delta_unwrap(b))) {
+               return fr_time_delta_overflow_add(a, b);
+       }
+       return fr_time_delta_wrap(out);
+}
 
 #define fr_time_delta_cond(_a, _op, _b) (fr_time_delta_unwrap(_a) _op fr_time_delta_unwrap(_b))
 #define fr_time_delta_gt(_a, _b) (fr_time_delta_unwrap(_a) > fr_time_delta_unwrap(_b))
@@ -190,8 +286,18 @@ static inline fr_time_delta_t fr_time_delta_mul(fr_time_delta_t a, fr_time_delta
  * @{
  */
 /* Don't add fr_unix_time_add_time_time, it's almost always a type error */
-static inline fr_unix_time_t fr_unix_time_add_time_delta(fr_unix_time_t a, fr_time_delta_t b) { return fr_unix_time_wrap(fr_unix_time_unwrap(a) + fr_time_delta_unwrap(b)); }
-static inline fr_unix_time_t fr_unix_time_add_delta_time(fr_time_delta_t a, fr_unix_time_t b) { return fr_unix_time_wrap(fr_time_delta_unwrap(a) + fr_unix_time_unwrap(b)); }
+static inline fr_unix_time_t fr_unix_time_add_time_delta(fr_unix_time_t a, fr_time_delta_t b)
+{
+       typeof_field(fr_unix_time_t, value) out;
+       if (!fr_add(&out, fr_unix_time_unwrap(a), fr_time_delta_unwrap(b))) return fr_unix_time_overflow_add(a, b);
+       return fr_unix_time_wrap(out);
+}
+static inline fr_unix_time_t fr_unix_time_add_delta_time(fr_time_delta_t a, fr_unix_time_t b)
+{
+       typeof_field(fr_unix_time_t, value) out;
+       if (!fr_add(&out, fr_time_delta_unwrap(a), fr_unix_time_unwrap(b))) return fr_unix_time_overflow_add(a, b);
+       return fr_unix_time_wrap(out);
+}
 
 /** Add a time/time delta together
  *
@@ -213,8 +319,18 @@ static inline fr_unix_time_t fr_unix_time_add_delta_time(fr_time_delta_t a, fr_u
                                  ) \
        )(_a, _b)
 
-static inline fr_time_delta_t fr_unix_time_sub_time_time(fr_unix_time_t a, fr_unix_time_t b) { return fr_time_delta_wrap(fr_unix_time_unwrap(a) - fr_unix_time_unwrap(b)); }
-static inline fr_unix_time_t fr_unix_time_sub_time_delta(fr_unix_time_t a, fr_time_delta_t b) { return fr_unix_time_wrap(fr_unix_time_unwrap(a) - fr_time_delta_unwrap(b)); }
+static inline fr_time_delta_t fr_unix_time_sub_time_time(fr_unix_time_t a, fr_unix_time_t b)
+{
+       typeof_field(fr_time_delta_t, value) out;
+       if (!fr_sub(&out, fr_unix_time_unwrap(a), fr_unix_time_unwrap(b))) return fr_time_delta_overflow_sub(a, b);
+       return fr_time_delta_wrap(out);
+}
+static inline fr_unix_time_t fr_unix_time_sub_time_delta(fr_unix_time_t a, fr_time_delta_t b)
+{
+       typeof_field(fr_unix_time_t, value) out;
+       if (!fr_sub(&out, fr_unix_time_unwrap(a), fr_time_delta_unwrap(b))) return fr_unix_time_overflow_sub(a, b);
+       return fr_unix_time_wrap(out);
+}
 
 /** Subtract one time from another
  *
@@ -243,16 +359,6 @@ static inline fr_unix_time_t fr_unix_time_sub_time_delta(fr_unix_time_t a, fr_ti
 #define fr_unix_time_ispos(_a) (fr_unix_time_unwrap(_a) > 0)
 /** @} */
 
-/** The base resolution for print parse operations
- */
-typedef enum {
-       FR_TIME_RES_SEC = 0,
-       FR_TIME_RES_CSEC,
-       FR_TIME_RES_MSEC,
-       FR_TIME_RES_USEC,
-       FR_TIME_RES_NSEC
-} fr_time_res_t;
-
 typedef struct {
        uint64_t        array[8];               //!< 100ns to 100s
 } fr_time_elapsed_t;
@@ -275,6 +381,18 @@ extern uint64_t                            our_mach_epoch;
  *
  * @{
  */
+static inline fr_unix_time_t fr_unix_time_from_integer(bool *overflow, int64_t integer, fr_time_res_t res)
+{
+       int64_t out;
+       if (res == FR_TIME_RES_INVALID) return fr_unix_time_max();
+       if (!fr_multiply(&out, integer, fr_time_multiplier_by_res[res])) {
+               if (overflow) *overflow = true;
+               return fr_unix_time_max();
+       }
+       if (overflow) *overflow = false;
+       return fr_unix_time_wrap(out);
+}
+
 static inline fr_unix_time_t fr_unix_time_from_nsec(int64_t nsec)
 {
        return fr_unix_time_wrap(nsec);
@@ -282,32 +400,65 @@ static inline fr_unix_time_t fr_unix_time_from_nsec(int64_t nsec)
 
 static inline fr_unix_time_t fr_unix_time_from_usec(int64_t usec)
 {
-       return fr_unix_time_wrap(usec * (NSEC / USEC));
+       uint64_t out;
+       if (!fr_multiply(&out, usec, (NSEC / USEC))) return (usec > 0) ? fr_unix_time_max() : fr_unix_time_min();
+       return fr_unix_time_wrap(out);
 }
 
 static inline fr_unix_time_t fr_unix_time_from_msec(int64_t msec)
 {
-       return fr_unix_time_wrap(msec * (NSEC / MSEC));
+       uint64_t out;
+       if (!fr_multiply(&out, msec, (NSEC / MSEC))) return (msec > 0) ? fr_unix_time_max() : fr_unix_time_min();
+       return fr_unix_time_wrap(out);
 }
 
 static inline fr_unix_time_t fr_unix_time_from_csec(int64_t csec)
 {
-       return fr_unix_time_wrap(csec * (NSEC / CSEC));
+       uint64_t out;
+       if (!fr_multiply(&out, csec, (NSEC / CSEC))) return (csec > 0) ? fr_unix_time_max() : fr_unix_time_min();
+       return fr_unix_time_wrap(out);
 }
 
 static inline fr_unix_time_t fr_unix_time_from_sec(int64_t sec)
 {
-       return fr_unix_time_wrap(sec * NSEC);
+       uint64_t out;
+       if (!fr_multiply(&out, sec, NSEC)) return (sec > 0) ? fr_unix_time_max() : fr_unix_time_min();
+       return fr_unix_time_wrap(out);
 }
 
 static inline CC_HINT(nonnull) fr_unix_time_t fr_unix_time_from_timeval(struct timeval const *tv)
 {
-       return fr_unix_time_wrap((((typeof_field(fr_unix_time_t, value)) tv->tv_sec) * NSEC) + (((typeof_field(fr_unix_time_t, value)) tv->tv_usec) * (NSEC / USEC)));
+       typeof_field(fr_unix_time_t, value) integer, fraction, out;
+
+       if (!fr_multiply(&integer, (typeof_field(fr_unix_time_t, value)) tv->tv_sec, NSEC)) {
+       overflow:
+               return fr_unix_time_max();
+       }
+
+       if (!fr_multiply(&fraction,
+                        (typeof_field(fr_unix_time_t, value)) tv->tv_usec, (NSEC / USEC))) goto overflow;
+
+       if (!fr_add(&out, integer, fraction)) goto overflow;
+
+       return fr_unix_time_wrap(out);
 }
 
 static inline CC_HINT(nonnull) fr_unix_time_t fr_unix_time_from_timespec(struct timespec const *ts)
 {
-       return fr_unix_time_wrap((((typeof_field(fr_unix_time_t, value))ts->tv_sec) * NSEC) + ts->tv_nsec);
+       typeof_field(fr_unix_time_t, value) integer, out;
+
+       if (!fr_multiply(&integer, (typeof_field(fr_unix_time_t, value)) ts->tv_sec, NSEC)) {
+       overflow:
+               return fr_unix_time_max();
+       }
+       if (!fr_add(&out, integer, ts->tv_nsec)) goto overflow;
+
+       return fr_unix_time_wrap(out);
+}
+
+static inline int64_t fr_unix_time_to_integer(fr_unix_time_t delta, fr_time_res_t res)
+{
+       return fr_unix_time_unwrap(delta) / fr_time_multiplier_by_res[res];
 }
 
 static inline int64_t fr_unix_time_to_usec(fr_unix_time_t delta)
@@ -330,6 +481,21 @@ static inline int64_t fr_unix_time_to_sec(fr_unix_time_t delta)
        return (fr_unix_time_unwrap(delta) / NSEC);
 }
 
+static inline int64_t fr_unix_time_to_min(fr_unix_time_t delta)
+{
+       return (fr_unix_time_unwrap(delta) / NSEC) / 60;
+}
+
+static inline int64_t fr_unix_time_to_hour(fr_unix_time_t delta)
+{
+       return (fr_unix_time_unwrap(delta) / NSEC) / 3600;
+}
+
+static inline int64_t fr_unix_time_to_day(fr_unix_time_t delta)
+{
+       return (fr_unix_time_unwrap(delta) / NSEC) / 386400;
+}
+
 /** Covert a time_t into out internal fr_unix_time_t
  *
  * Our internal unix time representation is unsigned and in nanoseconds which
@@ -342,7 +508,7 @@ static inline int64_t fr_unix_time_to_sec(fr_unix_time_t delta)
  */
 static inline CC_HINT(nonnull) fr_unix_time_t fr_unix_time_from_time(time_t time)
 {
-       if (time < 0) return fr_unix_time_wrap(0);
+       if (time < 0) return fr_unix_time_min();
 
        return fr_unix_time_wrap(time * NSEC);
 }
@@ -352,6 +518,21 @@ static inline CC_HINT(nonnull) fr_unix_time_t fr_unix_time_from_time(time_t time
  *
  * @{
  */
+static inline fr_time_delta_t fr_time_delta_from_integer(bool *overflow, int64_t integer, fr_time_res_t res)
+{
+       int64_t out;
+       if (res == FR_TIME_RES_INVALID) {
+               if (overflow) *overflow = true;
+               return fr_time_delta_max();
+       }
+       if (!fr_multiply(&out, integer, fr_time_multiplier_by_res[res])) {
+               if (overflow) *overflow = true;
+               return fr_time_delta_wrap(integer > 0 ? INT64_MAX: INT64_MIN);
+       }
+       if (overflow) *overflow = false;
+       return fr_time_delta_wrap(out);
+}
+
 static inline fr_time_delta_t fr_time_delta_from_nsec(int64_t nsec)
 {
        return fr_time_delta_wrap(nsec);
@@ -359,32 +540,65 @@ static inline fr_time_delta_t fr_time_delta_from_nsec(int64_t nsec)
 
 static inline fr_time_delta_t fr_time_delta_from_usec(int64_t usec)
 {
-       return fr_time_delta_wrap(usec * (NSEC / USEC));
+       int64_t out;
+       if (!fr_multiply(&out, usec, (NSEC / USEC))) return (usec > 0) ? fr_time_delta_max() : fr_time_delta_min();
+       return fr_time_delta_wrap(out);
 }
 
 static inline fr_time_delta_t fr_time_delta_from_msec(int64_t msec)
 {
-       return fr_time_delta_wrap(msec * (NSEC / MSEC));
+       int64_t out;
+       if (!fr_multiply(&out, msec, (NSEC / MSEC))) return (msec > 0) ? fr_time_delta_max() : fr_time_delta_min();
+       return fr_time_delta_wrap(out);
 }
 
 static inline fr_time_delta_t fr_time_delta_from_csec(int64_t csec)
 {
-       return fr_time_delta_wrap(csec * (NSEC / CSEC));
+       int64_t out;
+       if (!fr_multiply(&out, csec, (NSEC / CSEC))) return (csec > 0) ? fr_time_delta_max() : fr_time_delta_min();
+       return fr_time_delta_wrap(out);
 }
 
 static inline fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
 {
-       return fr_time_delta_wrap(sec * NSEC);
+       int64_t out;
+       if (!fr_multiply(&out, sec, NSEC)) return (sec > 0) ? fr_time_delta_max() : fr_time_delta_min();
+       return fr_time_delta_wrap(out);
 }
 
 static inline CC_HINT(nonnull) fr_time_delta_t fr_time_delta_from_timeval(struct timeval const *tv)
 {
-       return fr_time_delta_wrap((((typeof_field(fr_time_delta_t, value))tv->tv_sec) * NSEC) + (((typeof_field(fr_time_delta_t, value)) tv->tv_usec) * (NSEC / USEC)));
+       typeof_field(fr_time_delta_t, value) integer, fraction, out;
+
+       if (!fr_multiply(&integer, (typeof_field(fr_time_delta_t, value)) tv->tv_sec, NSEC)) {
+       overflow:
+               return fr_time_delta_max();
+       }
+
+       if (!fr_multiply(&fraction,
+                        (typeof_field(fr_time_delta_t, value)) tv->tv_usec, (NSEC / USEC))) goto overflow;
+
+       if (!fr_add(&out, integer, fraction)) goto overflow;
+
+       return fr_time_delta_wrap(out);
 }
 
 static inline CC_HINT(nonnull) fr_time_delta_t fr_time_delta_from_timespec(struct timespec const *ts)
 {
-       return fr_time_delta_wrap((((typeof_field(fr_time_delta_t, value))ts->tv_sec) * NSEC) + ts->tv_nsec);
+       typeof_field(fr_time_delta_t, value) integer, out;
+
+       if (!fr_multiply(&integer, (typeof_field(fr_time_delta_t, value)) ts->tv_sec, NSEC)) {
+       overflow:
+               return fr_time_delta_max();
+       }
+       if (!fr_add(&out, integer, ts->tv_nsec)) goto overflow;
+
+       return fr_time_delta_wrap(out);
+}
+
+static inline int64_t fr_time_delta_to_integer(fr_time_delta_t delta, fr_time_res_t res)
+{
+       return fr_time_delta_unwrap(delta) / fr_time_multiplier_by_res[res];
 }
 
 static inline int64_t fr_time_delta_to_usec(fr_time_delta_t delta)
@@ -440,12 +654,33 @@ static inline int64_t fr_time_wallclock_at_last_sync(void)
        return atomic_load_explicit(&our_realtime, memory_order_consume);
 }
 
+/** Convert an fr_time_t (internal time) to arbitrary unit as wallclock time
+ *
+ */
+static inline int64_t fr_time_to_integer(bool *overflow, fr_time_t when, fr_time_res_t res)
+{
+       int64_t out;
+
+       if (!fr_add(&out, fr_time_unwrap(when) / fr_time_multiplier_by_res[res],
+                   atomic_load_explicit(&our_realtime, memory_order_consume) / fr_time_multiplier_by_res[res])) {
+               if (overflow) *overflow = true;
+               return fr_time_unwrap(when) > 0 ? INT64_MAX : INT64_MIN;
+       }
+       if (overflow) *overflow = false;
+       return out;
+}
+
 /** Convert an fr_time_t (internal time) to our version of unix time (wallclock time)
  *
  */
 static inline fr_unix_time_t fr_time_to_unix_time(fr_time_t when)
 {
-       return fr_unix_time_wrap(fr_time_unwrap(when) + atomic_load_explicit(&our_realtime, memory_order_consume));
+       int64_t out;
+
+       if (!fr_add(&out, fr_time_unwrap(when), atomic_load_explicit(&our_realtime, memory_order_consume))) {
+               return fr_time_unwrap(when) ? fr_unix_time_max() : fr_unix_time_min();
+       }
+       return fr_unix_time_wrap(out);
 }
 
 /** Convert an fr_time_t (internal time) to number of usec since the unix epoch (wallclock time)
@@ -453,7 +688,9 @@ static inline fr_unix_time_t fr_time_to_unix_time(fr_time_t when)
  */
 static inline int64_t fr_time_to_usec(fr_time_t when)
 {
-       return ((fr_time_unwrap(when) + atomic_load_explicit(&our_realtime, memory_order_consume)) / (NSEC / USEC));
+       /* Divide each operand separately to avoid overflow on addition */
+       return (((fr_time_unwrap(when) / (NSEC / USEC)) +
+               (atomic_load_explicit(&our_realtime, memory_order_consume) / (NSEC / USEC))));
 }
 
 /** Convert an fr_time_t (internal time) to number of msec since the unix epoch (wallclock time)
@@ -461,7 +698,9 @@ static inline int64_t fr_time_to_usec(fr_time_t when)
  */
 static inline int64_t fr_time_to_msec(fr_time_t when)
 {
-       return ((fr_time_unwrap(when) + atomic_load_explicit(&our_realtime, memory_order_consume)) / (NSEC / MSEC));
+       /* Divide each operand separately to avoid overflow on addition */
+       return (((fr_time_unwrap(when) / (NSEC / MSEC)) +
+               (atomic_load_explicit(&our_realtime, memory_order_consume) / (NSEC / MSEC))));
 }
 
 /** Convert an fr_time_t (internal time) to number of csec since the unix epoch (wallclock time)
@@ -469,7 +708,9 @@ static inline int64_t fr_time_to_msec(fr_time_t when)
  */
 static inline int64_t fr_time_to_csec(fr_time_t when)
 {
-       return ((fr_time_unwrap(when) + atomic_load_explicit(&our_realtime, memory_order_consume)) / (NSEC / CSEC));
+       /* Divide each operand separately to avoid overflow on addition */
+       return (((fr_time_unwrap(when) / (NSEC / CSEC)) +
+               (atomic_load_explicit(&our_realtime, memory_order_consume) / (NSEC / CSEC))));
 }
 
 /** Convert an fr_time_t (internal time) to number of sec since the unix epoch (wallclock time)
@@ -477,7 +718,9 @@ static inline int64_t fr_time_to_csec(fr_time_t when)
  */
 static inline int64_t fr_time_to_sec(fr_time_t when)
 {
-       return ((fr_time_unwrap(when) + atomic_load_explicit(&our_realtime, memory_order_consume)) / NSEC);
+       /* Divide each operand separately to avoid overflow on addition */
+       return (((fr_time_unwrap(when) / NSEC) +
+               (atomic_load_explicit(&our_realtime, memory_order_consume) / NSEC)));
 }
 
 /** Convert server epoch time to unix epoch time
@@ -492,6 +735,34 @@ static inline int64_t fr_time_to_sec(fr_time_t when)
  */
 #define fr_time_to_timespec(_when) fr_time_delta_to_timespec(fr_time_delta_wrap(fr_time_wallclock_at_last_sync() + fr_time_unwrap(_when)))
 
+/** Convert wallclock time to a fr_time_t (internal time)
+ *
+ * @param[out] overflow        Whether the conversion overflowed.
+ * @param[in] when     The timestamp to convert.
+ * @param[in] res      The scale the integer value is in.
+ * @return
+ *     - >0 number of nanoseconds since the server started.
+ *     - 0 when the server started.
+ *     - <0 number of nanoseconds before the server started.
+ */
+static inline fr_time_t fr_time_from_integer(bool *overflow, int64_t when, fr_time_res_t res)
+{
+       typeof_field(fr_time_t, value) out;
+
+       if (!fr_multiply(&out, when, fr_time_multiplier_by_res[res])) {
+               if (overflow) *overflow = true;
+               return when > 0 ? fr_time_max() : fr_time_min();
+       }
+
+       if (!fr_sub(&out, out, atomic_load_explicit(&our_realtime, memory_order_consume))) {
+               if (overflow) *overflow = true;
+               return when < 0 ? fr_time_max() : fr_time_min();
+       }
+
+       if (overflow) *overflow = false;
+       return fr_time_wrap(out);
+}
+
 /** Convert a nsec (wallclock time) to a fr_time_t (internal time)
  *
  * @param[in] when     The timestamp to convert.
@@ -502,7 +773,12 @@ static inline int64_t fr_time_to_sec(fr_time_t when)
  */
 static inline fr_time_t fr_time_from_nsec(int64_t when)
 {
-       return fr_time_wrap((when * NSEC) - atomic_load_explicit(&our_realtime, memory_order_consume));
+       typeof_field(fr_time_t, value) out = fr_time_delta_unwrap(fr_time_delta_from_nsec(when));
+
+       if (!fr_sub(&out, out, atomic_load_explicit(&our_realtime, memory_order_consume))) {
+               return when > 0 ? fr_time_min() : fr_time_max();
+       }
+       return fr_time_wrap(out);
 }
 
 /** Convert usec (wallclock time) to a fr_time_t (internal time)
@@ -515,7 +791,12 @@ static inline fr_time_t fr_time_from_nsec(int64_t when)
  */
 static inline fr_time_t fr_time_from_usec(int64_t when)
 {
-       return fr_time_wrap((when * USEC) - atomic_load_explicit(&our_realtime, memory_order_consume));
+       typeof_field(fr_time_t, value) out = fr_time_delta_unwrap(fr_time_delta_from_usec(when));
+
+       if (!fr_sub(&out, out, atomic_load_explicit(&our_realtime, memory_order_consume))) {
+               return when > 0 ? fr_time_min() : fr_time_max();
+       }
+       return fr_time_wrap(out);
 }
 
 /** Convert msec (wallclock time) to a fr_time_t (internal time)
@@ -528,7 +809,12 @@ static inline fr_time_t fr_time_from_usec(int64_t when)
  */
 static inline fr_time_t fr_time_from_msec(int64_t when)
 {
-       return fr_time_wrap((when * MSEC) - atomic_load_explicit(&our_realtime, memory_order_consume));
+       typeof_field(fr_time_t, value) out = fr_time_delta_unwrap(fr_time_delta_from_msec(when));
+
+       if (!fr_sub(&out, out, atomic_load_explicit(&our_realtime, memory_order_consume))) {
+               return when > 0 ? fr_time_min() : fr_time_max();
+       }
+       return fr_time_wrap(out);
 }
 
 /** Convert csec (wallclock time) to a fr_time_t (internal time)
@@ -541,7 +827,12 @@ static inline fr_time_t fr_time_from_msec(int64_t when)
  */
 static inline fr_time_t fr_time_from_csec(int64_t when)
 {
-       return fr_time_wrap((when * CSEC) - atomic_load_explicit(&our_realtime, memory_order_consume));
+       typeof_field(fr_time_t, value) out = fr_time_delta_unwrap(fr_time_delta_from_csec(when));
+
+       if (!fr_sub(&out, out, atomic_load_explicit(&our_realtime, memory_order_consume))) {
+               return when > 0 ? fr_time_min() : fr_time_max();
+       }
+       return fr_time_wrap(out);
 }
 
 /** Convert a time_t (wallclock time) to a fr_time_t (internal time)
@@ -554,9 +845,16 @@ static inline fr_time_t fr_time_from_csec(int64_t when)
  */
 static inline fr_time_t fr_time_from_sec(time_t when)
 {
-       return fr_time_wrap((when * NSEC) - atomic_load_explicit(&our_realtime, memory_order_consume));
+       typeof_field(fr_time_t, value) out = fr_time_delta_unwrap(fr_time_delta_from_sec(when));
+
+       if (!fr_sub(&out, out, atomic_load_explicit(&our_realtime, memory_order_consume))) {
+               return when > 0 ? fr_time_min() : fr_time_max();
+       }
+       return fr_time_wrap(out);
 }
 
+
+
 /** Convert a timespec (wallclock time) to a fr_time_t (internal time)
  *
  * @param[in] when_ts  The timestamp to convert.
@@ -567,7 +865,12 @@ static inline fr_time_t fr_time_from_sec(time_t when)
  */
 static inline CC_HINT(nonnull) fr_time_t fr_time_from_timespec(struct timespec const *when_ts)
 {
-       return fr_time_wrap(fr_time_delta_unwrap(fr_time_delta_from_timespec(when_ts)) - atomic_load_explicit(&our_realtime, memory_order_consume));
+       typeof_field(fr_time_t, value) tmp = fr_time_delta_unwrap(fr_time_delta_from_timespec(when_ts)), out;
+
+       if (!fr_sub(&out, tmp, atomic_load_explicit(&our_realtime, memory_order_consume))) {
+               return tmp > 0 ? fr_time_min() : fr_time_max();
+       }
+       return fr_time_wrap(out);
 }
 
 /** Convert a timeval (wallclock time) to a fr_time_t (internal time)
@@ -580,7 +883,12 @@ static inline CC_HINT(nonnull) fr_time_t fr_time_from_timespec(struct timespec c
  */
 static inline CC_HINT(nonnull) fr_time_t fr_time_from_timeval(struct timeval const *when_tv)
 {
-       return fr_time_wrap(fr_time_delta_unwrap(fr_time_delta_from_timeval(when_tv)) - atomic_load_explicit(&our_realtime, memory_order_consume));
+       typeof_field(fr_time_t, value) tmp = fr_time_delta_unwrap(fr_time_delta_from_timeval(when_tv)), out;
+
+       if (!fr_sub(&out, tmp, atomic_load_explicit(&our_realtime, memory_order_consume))) {
+               return tmp > 0 ? fr_time_min() : fr_time_max();
+       }
+       return fr_time_wrap(out);
 }
 /** @} */
 
@@ -662,8 +970,6 @@ int                 fr_time_delta_from_str(fr_time_delta_t *out, char const *in, fr_time_res_t
 size_t         fr_time_strftime_local(fr_sbuff_t *out, fr_time_t time, char const *fmt) CC_HINT(format(strftime, 3, 0));
 size_t         fr_time_strftime_utc(fr_sbuff_t *out, fr_time_t time, char const *fmt)  CC_HINT(format(strftime, 3, 0));
 
-int64_t                fr_time_delta_scale(fr_time_delta_t delta, fr_time_res_t hint);
-
 void           fr_time_elapsed_update(fr_time_elapsed_t *elapsed, fr_time_t start, fr_time_t end) CC_HINT(nonnull);
 void           fr_time_elapsed_fprint(FILE *fp, fr_time_elapsed_t const *elapsed, char const *prefix, int tabs) CC_HINT(nonnull(1,2));
 
index 3483332a399c2ef9892f7feccc195e798f46fe1b..e7d33d9a0d12bed12fe109a63ad448a8de33b899 100644 (file)
@@ -1491,32 +1491,14 @@ ssize_t fr_value_box_to_network(fr_dbuff_t *dbuff, fr_value_box_t const *value)
        case FR_TYPE_DATE:
        {
                uint64_t date = 0;
+               fr_time_res_t res;
 
                if (!value->enumv) {
-                       goto date_seconds;
-
-               } else switch (value->enumv->flags.flag_time_res) {
-               date_seconds:
-               case FR_TIME_RES_SEC:
-                       date = fr_unix_time_to_sec(value->vb_date);
-                       break;
-
-               case FR_TIME_RES_CSEC:
-                       date = fr_unix_time_to_csec(value->vb_date);
-                       break;
-
-               case FR_TIME_RES_MSEC:
-                       date = fr_unix_time_to_msec(value->vb_date);
-                       break;
-
-               case FR_TIME_RES_USEC:
-                       date = fr_unix_time_to_usec(value->vb_date);
-                       break;
-
-               case FR_TIME_RES_NSEC:
-                       date = fr_unix_time_to_usec(value->vb_date);
-                       break;
+                       res = FR_TIME_RES_SEC;
+               } else {
+                       res = value->enumv->flags.flag_time_res;
                }
+               date = fr_unix_time_to_integer(value->vb_date, res);
 
                if (!value->enumv) {
                        goto date_size4;
@@ -1547,32 +1529,10 @@ ssize_t fr_value_box_to_network(fr_dbuff_t *dbuff, fr_value_box_t const *value)
        case FR_TYPE_TIME_DELTA:
        {
                int64_t date = 0;       /* may be negative */
+               fr_time_res_t res = FR_TIME_RES_SEC;
+               if (value->enumv) res = value->enumv->flags.flag_time_res;
 
-               if (!value->enumv) {
-                       goto delta_seconds;
-
-               } switch (value->enumv->flags.flag_time_res) {
-               delta_seconds:
-               case FR_TIME_RES_SEC:
-                       date = fr_time_delta_to_sec(value->vb_time_delta);
-                       break;
-
-               case FR_TIME_RES_CSEC:
-                       date = fr_time_delta_to_csec(value->vb_time_delta);
-                       break;
-
-               case FR_TIME_RES_MSEC:
-                       date = fr_time_delta_to_msec(value->vb_time_delta);
-                       break;
-
-               case FR_TIME_RES_USEC:
-                       date = fr_time_delta_to_usec(value->vb_time_delta);
-                       break;
-
-               case FR_TIME_RES_NSEC:
-                       date = fr_time_delta_unwrap(value->vb_time_delta);
-                       break;
-               }
+               date = fr_time_delta_to_integer(value->vb_time_delta, res);
 
                if (!value->enumv) {
                        goto delta_size4;
@@ -1878,7 +1838,12 @@ ssize_t fr_value_box_from_network(TALLOC_CTX *ctx,
 
                FR_DBUFF_OUT_UINT64V_RETURN(&date, &work_dbuff, length);
 
-               dst->vb_date = fr_unix_time_wrap(fr_time_scale(date, precision));
+               if (!fr_multiply(&date, date, fr_time_multiplier_by_res[precision])) {
+                       fr_strerror_const("date would overflow");
+                       return 0;
+               }
+
+               dst->vb_date = fr_unix_time_wrap(date);
        }
                break;
 
@@ -2809,30 +2774,12 @@ static inline int fr_value_box_cast_integer_to_integer(UNUSED TALLOC_CTX *ctx, f
         *      nanoseconds -> seconds.
         */
        case FR_TYPE_DATE:
-               if (dst->enumv) {
-                       switch (dst->enumv->flags.flag_time_res) {
-                       date_src_seconds:
-                       case FR_TIME_RES_SEC:
-                               tmp = fr_unix_time_to_sec(src->vb_date);
-                               break;
-
-                       case FR_TIME_RES_CSEC:
-                               tmp = fr_unix_time_to_csec(src->vb_date);
-                               break;
-
-                       case FR_TIME_RES_USEC:
-                               tmp = fr_unix_time_to_usec(src->vb_date);
-                               break;
-
-                       case FR_TIME_RES_MSEC:
-                               tmp = fr_unix_time_to_msec(src->vb_date);
-                               break;
+       {
+               fr_time_res_t res = FR_TIME_RES_SEC;
+               if (dst->enumv) res = dst->enumv->flags.flag_time_res;
 
-                       case FR_TIME_RES_NSEC:
-                               tmp = fr_unix_time_unwrap(src->vb_date);
-                               break;
-                       }
-               } else goto date_src_seconds;
+               tmp = fr_unix_time_to_integer(src->vb_date, res);
+       }
                break;
 
        /*
@@ -2842,30 +2789,13 @@ static inline int fr_value_box_cast_integer_to_integer(UNUSED TALLOC_CTX *ctx, f
         *      signed integer for comparisons.
         */
        case FR_TYPE_TIME_DELTA:
-               if (dst->enumv) {
-                       switch (dst->enumv->flags.flag_time_res) {
-                       delta_src_seconds:
-                       case FR_TIME_RES_SEC:
-                               tmp = (uint64_t)fr_time_delta_to_sec(src->vb_time_delta);
-                               break;
-
-                       case FR_TIME_RES_CSEC:
-                               tmp = (uint64_t)fr_time_delta_to_csec(src->vb_time_delta);
-                               break;
-
-                       case FR_TIME_RES_USEC:
-                               tmp = (uint64_t)fr_time_delta_to_usec(src->vb_time_delta);
-                               break;
+       {
+               fr_time_res_t res = FR_TIME_RES_SEC;
 
-                       case FR_TIME_RES_MSEC:
-                               tmp = (uint64_t)fr_time_delta_to_msec(src->vb_time_delta);
-                               break;
+               if (dst->enumv) res = dst->enumv->flags.flag_time_res;
 
-                       case FR_TIME_RES_NSEC:
-                               tmp = (uint64_t)fr_time_delta_unwrap(src->vb_time_delta);
-                               break;
-                       }
-               } else goto delta_src_seconds;
+               tmp = (uint64_t)fr_time_delta_to_integer(src->vb_time_delta, res);
+       }
                break;
 
        default:
@@ -2908,58 +2838,32 @@ static inline int fr_value_box_cast_integer_to_integer(UNUSED TALLOC_CTX *ctx, f
        fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
        switch (dst_type) {
        case FR_TYPE_DATE:
-               if (dst->enumv) {
-                       switch (dst->enumv->flags.flag_time_res) {
-                       date_dst_seconds:
-                       case FR_TIME_RES_SEC:
-                               dst->vb_date = fr_unix_time_from_sec(tmp);
-                               break;
-
-                       case FR_TIME_RES_CSEC:
-                               dst->vb_date = fr_unix_time_from_csec(tmp);
-                               break;
-
-                       case FR_TIME_RES_USEC:
-                               dst->vb_date = fr_unix_time_from_usec(tmp);
-                               break;
-
-                       case FR_TIME_RES_MSEC:
-                               dst->vb_date = fr_unix_time_from_msec(tmp);
-                               break;
+       {
+               bool overflow;
+               fr_time_res_t res = FR_TIME_RES_SEC;
+               if (dst->enumv) res = dst->enumv->flags.flag_time_res;
 
-                       case FR_TIME_RES_NSEC:
-                               dst->vb_date = fr_unix_time_from_nsec(tmp);
-                               break;
-                       }
-               } else goto date_dst_seconds;
+               dst->vb_date = fr_unix_time_from_integer(&overflow, tmp, res);
+               if (overflow) {
+                       fr_strerror_const("Input to data type would overflow");
+                       return -1;
+               }
+       }
                break;
 
        case FR_TYPE_TIME_DELTA:
-               if (dst->enumv) {
-                       switch (dst->enumv->flags.flag_time_res) {
-                       delta_dst_seconds:
-                       case FR_TIME_RES_SEC:
-                               dst->vb_time_delta = fr_time_delta_from_sec(tmp);
-                               break;
-
-                       case FR_TIME_RES_CSEC:
-                               dst->vb_time_delta = fr_time_delta_from_csec(tmp);
-                               break;
-
-                       case FR_TIME_RES_USEC:
-                               dst->vb_time_delta = fr_time_delta_from_usec(tmp);
-                               break;
-
-                       case FR_TIME_RES_MSEC:
-                               dst->vb_time_delta = fr_time_delta_from_msec(tmp);
-                               break;
+       {
+               bool overflow;
+               fr_time_res_t res = FR_TIME_RES_SEC;
+               if (dst->enumv) res = dst->enumv->flags.flag_time_res;
 
-                       case FR_TIME_RES_NSEC:
-                               dst->vb_time_delta = fr_time_delta_from_nsec(tmp);
-                               break;
-                       }
-                } else goto delta_dst_seconds;
-                break;
+               dst->vb_time_delta = fr_time_delta_from_integer(&overflow, tmp, res);
+               if (overflow) {
+                       fr_strerror_const("Input to time_delta type would overflow");
+                       return -1;
+               }
+       }
+               break;
 
        default:
 #ifdef WORDS_BIGENDIAN
@@ -5064,6 +4968,9 @@ ssize_t fr_value_box_print(fr_sbuff_t *out, fr_value_box_t const *data, fr_sbuff
                 *      formats.  The RFC is much stricter.
                 */
                switch (data->enumv->flags.flag_time_res) {
+               case FR_TIME_RES_DAY:
+               case FR_TIME_RES_HOUR:
+               case FR_TIME_RES_MIN:
                case FR_TIME_RES_SEC:
                        break;
 
@@ -5113,7 +5020,6 @@ ssize_t fr_value_box_print(fr_sbuff_t *out, fr_value_box_t const *data, fr_sbuff
                int64_t         lhs = 0;
                uint64_t        rhs = 0;
                fr_time_res_t   res = FR_TIME_RES_SEC;
-
                if (data->enumv) res = data->enumv->flags.flag_time_res;
 
 /*
@@ -5122,32 +5028,8 @@ ssize_t fr_value_box_print(fr_sbuff_t *out, fr_value_box_t const *data, fr_sbuff
  */
 #define MOD(a,b) (((a<0) ? (-a) : (a))%(b))
 
-               switch (res) {
-               case FR_TIME_RES_SEC:
-                       lhs = fr_time_delta_to_sec(data->datum.time_delta);
-                       rhs = MOD(fr_time_delta_unwrap(data->datum.time_delta), NSEC);
-                       break;
-
-               case FR_TIME_RES_CSEC:
-                       lhs = fr_time_delta_to_csec(data->datum.time_delta);
-                       rhs = MOD(fr_time_delta_unwrap(data->datum.time_delta), (NSEC / CSEC));
-                       break;
-
-               case FR_TIME_RES_MSEC:
-                       lhs = fr_time_delta_to_msec(data->datum.time_delta);
-                       rhs = MOD(fr_time_delta_unwrap(data->datum.time_delta), (NSEC / MSEC));
-                       break;
-
-               case FR_TIME_RES_USEC:
-                       lhs = fr_time_delta_to_usec(data->datum.time_delta);
-                       rhs = MOD(fr_time_delta_unwrap(data->datum.time_delta), (NSEC / USEC));
-                       break;
-
-               case FR_TIME_RES_NSEC:
-                       lhs = fr_time_delta_unwrap(data->datum.time_delta);
-                       rhs = 0;
-                       break;
-               }
+               lhs = fr_time_delta_to_integer(data->datum.time_delta, res);
+               rhs = MOD(fr_time_delta_unwrap(data->datum.time_delta), fr_time_multiplier_by_res[res]);
 
                if (!data->enumv || !data->enumv->flags.is_unsigned) {
                        /*
index 576a86814eae3eca0fd9631382d3f52a91834067..a0a1bf2f7f1941b48204cd49f1c7425ee64d7434 100644 (file)
@@ -274,7 +274,7 @@ static bool get_number(request_t *request, char const **string, int64_t *answer)
                                 *      integer number of milliseconds
                                 */
                        case FR_TYPE_TIME_DELTA:
-                               y = fr_time_delta_scale(vp->vp_time_delta, vp->data.enumv ? vp->data.enumv->flags.flag_time_res : FR_TIME_RES_SEC);
+                               y = fr_time_delta_to_integer(vp->vp_time_delta, vp->data.enumv ? vp->data.enumv->flags.flag_time_res : FR_TIME_RES_SEC);
                                break;
 
                        case FR_TYPE_DATE: