]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
add fr_type_cast()
authorAlan T. DeKok <aland@freeradius.org>
Fri, 8 Jan 2021 14:49:49 +0000 (09:49 -0500)
committerAlan T. DeKok <aland@freeradius.org>
Sat, 9 Jan 2021 20:02:15 +0000 (15:02 -0500)
which checks if you can cast type src->dst

src/lib/util/types.h
src/lib/util/value.c

index b357bf77cfca22b8f7ec6a873b55d68a30c1f4a1..4f5bf8b7ad6d3056375b8a2aef9793d228393e9c 100644 (file)
@@ -31,6 +31,7 @@ extern "C" {
 
 /** Internal data types used within libfreeradius
  *
+ *  Order is important!  Please see fr_type_promote() for details.
  */
 typedef enum {
        FR_TYPE_INVALID = 0,                    //!< Invalid (uninitialised) attribute type.
@@ -65,10 +66,10 @@ typedef enum {
        FR_TYPE_FLOAT32,                        //!< Single precision floating point.
        FR_TYPE_FLOAT64,                        //!< Double precision floating point.
 
-       FR_TYPE_DATE,                           //!< 32 Bit Unix timestamp.
-
        FR_TYPE_TIME_DELTA,                     //!< A period of time measured in nanoseconds.
 
+       FR_TYPE_DATE,                           //!< Unix time stamp, always has value >2^31
+
        FR_TYPE_TLV,                            //!< Contains nested attributes.
        FR_TYPE_STRUCT,                         //!< like TLV, but without T or L, and fixed-width children
 
@@ -210,6 +211,11 @@ typedef enum {
        FR_TYPE_STRING: \
        case FR_TYPE_DATE
 
+/*
+ *  In value.c, but should likely be here.
+ */
+bool fr_type_cast(fr_type_t dst, fr_type_t src);
+
 #ifdef __cplusplus
 }
 #endif
index 421a03758efc3b54b9e31efa57bfbd8710c3495d..fc88522c3d3ef0a1050c0137cd307dedfdb45398 100644 (file)
@@ -5181,3 +5181,106 @@ fr_value_box_t *fr_value_box_list_get(fr_value_box_t *head, int index)
 
        return head;
 }
+
+#define O(_x) [FR_TYPE_ ## _x] = true
+
+/*
+ *     Can we promote [src][dst] -> dst
+ *             dst is not octets / string
+ *             src and dst are both FR_TYPE_VALUE
+ */
+static const bool type_promote_table[FR_TYPE_MAX][FR_TYPE_MAX] = {
+       [FR_TYPE_IPV4_ADDR] = {
+               O(IPV4_PREFIX),
+               O(IPV6_ADDR),
+               O(IPV6_PREFIX),
+               O(UINT32), /* ipv4 addresses are uint32 */
+       },
+       [FR_TYPE_IPV4_PREFIX] = {
+               O(IPV4_ADDR),   /* if the prefix is /32 */
+               O(IPV6_ADDR),
+               O(IPV6_PREFIX),
+       },
+       [FR_TYPE_IPV6_ADDR] = {
+               O(IPV6_PREFIX),
+       },
+       [FR_TYPE_IPV6_PREFIX] = {
+               O(IPV6_ADDR),   /* if the prefix is /128 */
+       },
+
+       [FR_TYPE_ETHERNET] = {
+               O(UINT64),
+       },
+
+       [FR_TYPE_UINT64] = {
+               O(ETHERNET),
+       },
+
+       [FR_TYPE_DATE] = {      /* in 2021, dates always have values 2^31 or more */
+               O(UINT32),
+               O(UINT64),
+               O(INT32),
+               O(INT64),
+               O(SIZE),
+               O(FLOAT32),
+               O(FLOAT64),
+               O(TIME_DELTA),
+       },
+
+       [FR_TYPE_TIME_DELTA] = {
+               O(DATE),
+       },
+
+       [FR_TYPE_UINT32] = {
+               O(IPV4_ADDR),
+       },
+
+};
+
+
+/** Return if we're allowed to cast the types.
+ *
+ * @param dst  the destination type we wish to cast to
+ * @param src  the source type we wish to cast to
+ *
+ */
+bool fr_type_cast(fr_type_t dst, fr_type_t src)
+{
+       /*
+        *      Invalid casts.
+        */
+       if ((dst == FR_TYPE_INVALID) || (src >= FR_TYPE_TLV)) return false;
+       if ((src == FR_TYPE_INVALID) || (dst >= FR_TYPE_TLV)) return false;
+
+       if (src == dst) return true;
+
+       /*
+        *      Anything can be converted to octets or strings.
+        */
+       if (dst == FR_TYPE_OCTETS) return true;
+       if (dst == FR_TYPE_STRING) return true;
+
+       /*
+        *      Strings and octets can be converted to anything.  We
+        *      do run-time checks on the values to see if they fit.
+        */
+       if (src == FR_TYPE_OCTETS) return true;
+       if (src == FR_TYPE_STRING) return true;
+
+       /*
+        *      Any integer-style thing can be cast to any other
+        *      integer-style thing.  Mostly.  We do run-time checks
+        *      on values to see if they fit.
+        */
+       if (((src >= FR_TYPE_BOOL) && (src <= FR_TYPE_TIME_DELTA)) &&
+           ((dst >= FR_TYPE_BOOL) && (dst <= FR_TYPE_TIME_DELTA))) {
+               return true;
+       }
+
+       /*
+        *      That takes care of the simple cases.  :( Now to the
+        *      complex ones.  Instead of masses of if / then / else,
+        *      we just use a lookup table.
+        */
+       return type_promote_table[src][dst];
+}