From: Alan T. DeKok Date: Fri, 10 Sep 2021 18:46:40 +0000 (-0400) Subject: add fr_time_delta_scale(), and use it in rlm_expr X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e815e617f7dc493faf80294f6ac93c59bc1512fb;p=thirdparty%2Ffreeradius-server.git add fr_time_delta_scale(), and use it in rlm_expr so that when we do calculations based on an attribute of type "time_delta", and of precision "milliseconds", we can use 5 milliseconds as "5", and not as "0.0005" --- diff --git a/src/lib/util/time.c b/src/lib/util/time.c index 213d4e580c1..752d0e024f3 100644 --- a/src/lib/util/time.c +++ b/src/lib/util/time.c @@ -296,7 +296,7 @@ int fr_time_delta_from_str(fr_time_delta_t *out, char const *in, fr_time_res_t h */ if ((p[1] == 's') && (p[2] == '\0')) { if (p[0] == 'm') { - scale = 1000000; /* 1,000,000 nanoeconds in a millisecond */ + scale = 1000000; /* 1,000,000 nanoseconds in a millisecond */ goto done; } @@ -600,3 +600,25 @@ 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 delta / NSEC; + + case FR_TIME_RES_MSEC: + return delta / 1000000; + + case FR_TIME_RES_USEC: + return delta / 1000; + + case FR_TIME_RES_NSEC: + return delta; + + default: + break; + } + + return 0; +} diff --git a/src/lib/util/time.h b/src/lib/util/time.h index d4491f5a74c..8c7e51c2527 100644 --- a/src/lib/util/time.h +++ b/src/lib/util/time.h @@ -369,6 +369,8 @@ 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)); fr_unix_time_t fr_unix_time_from_tm(struct tm *tm) CC_HINT(nonnull); diff --git a/src/modules/rlm_expr/rlm_expr.c b/src/modules/rlm_expr/rlm_expr.c index 3330d234508..9a776a80f00 100644 --- a/src/modules/rlm_expr/rlm_expr.c +++ b/src/modules/rlm_expr/rlm_expr.c @@ -250,7 +250,51 @@ static bool get_number(request_t *request, char const **string, int64_t *answer) int64_t y; fr_value_box_t value; - if (vp->vp_type != FR_TYPE_UINT64) { + switch (vp->vp_type) { + case FR_TYPE_UINT64: + if (vp->vp_uint64 > INT64_MAX) { + /* + * So we can print out the correct value + * in the overflow error message. + */ + fr_value_box_copy(NULL, &value, &vp->data); + goto overflow; + } + y = (int64_t)vp->vp_uint64; + break; + + case FR_TYPE_INT64: + y = vp->vp_int64; + break; + + /* + * Scale the time_delta to whatever precision is defined by the + * attribute. This is generally what the user expects. i.e. if + * the attribute says it's in milliseconds, then print out an + * 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); + break; + + case FR_TYPE_DATE: + /* + * This is wrong... we should really do scaling, but internally + * we have vp_date as fr_unix_time_t, and not as fr_time_t. + * + * Perhaps a better solution is to simply have the dictionaries + * disallow any precision for the 'date' data type. + */ + y = fr_unix_time_to_sec(vp->vp_date); + break; + + case FR_TYPE_STRUCTURAL: + REDEBUG("Cannot convert %s of type '%s' to integer", + fr_table_str_by_value(fr_value_box_type_table, vp->vp_type, "?Unknown?")); + break; + break; + + default: if (fr_value_box_cast(vp, &value, FR_TYPE_UINT64, NULL, &vp->data) < 0) { RPEDEBUG("Failed converting &%.*s to an integer value", (int) vpt->len, vpt->name); @@ -270,16 +314,7 @@ static bool get_number(request_t *request, char const **string, int64_t *answer) RINDENT(); RDEBUG3("&%.*s --> %" PRIu64, (int)vpt->len, vpt->name, y); REXDENT(); - } else { - if (vp->vp_uint64 > INT64_MAX) { - /* - * So we can print out the correct value - * in the overflow error message. - */ - fr_value_box_copy(NULL, &value, &vp->data); - goto overflow; - } - y = (int64_t)vp->vp_uint64; + break; } /*