]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
add fr_time_delta_scale(), and use it in rlm_expr
authorAlan T. DeKok <aland@freeradius.org>
Fri, 10 Sep 2021 18:46:40 +0000 (14:46 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Sat, 11 Sep 2021 10:41:59 +0000 (06:41 -0400)
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"

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

index 213d4e580c1b935883cdb85c963651d17af509b9..752d0e024f33bcaa6cf20e95e697b30f82459ed7 100644 (file)
@@ -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;
+}
index d4491f5a74c3f456354794d69ed4beed1ecb8f10..8c7e51c2527065598fdeac6936a8de34ecbca2e0 100644 (file)
@@ -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);
index 3330d234508137b10496871054be7c31ad0db1cd..9a776a80f002abb00b58209f398c850bd790613d 100644 (file)
@@ -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;
                        }
 
                        /*