From: Arran Cudbard-Bell Date: Thu, 13 Jul 2017 19:07:38 +0000 (-0400) Subject: Add unboxing macro X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3be457d0613d4b64bf2bdaafdd1d73950265e204;p=thirdparty%2Ffreeradius-server.git Add unboxing macro Move some functions to static inline Remove 'from' from some functions names (box is a verb). --- diff --git a/src/include/value.h b/src/include/value.h index 978b9ce0ed8..8144a6d90b7 100644 --- a/src/include/value.h +++ b/src/include/value.h @@ -19,6 +19,7 @@ #include #include #include +#include /* * Avoid circular type references. @@ -201,6 +202,7 @@ struct value_box { #define fr_box_timeval(_val) _fr_box(FR_TYPE_TIMEVAL, .vb_timeval, _val) /* @} **/ + /** @name Value box assignment functions * * These functions allow C values to be assigned to value boxes. @@ -208,36 +210,95 @@ struct value_box { * * @{ */ -#define FR_VALUE_BOX_FROM(_ctype, _field, _type) \ -static inline int fr_value_box_from_##_field(fr_value_box_t *dst, fr_dict_attr_t const *enumv, _ctype value, bool tainted) { \ - dst->type = _type; \ + +/** Initialise a fr_value_box_t + * + * The value should be set later with one of the fr_value_box_* functions. + * + * @param[in] box to initialise. + * @param[in] type to set. + * @param[in] enumv Enumeration values. + * @param[in] tainted Whether data will come from an untrusted source. + */ +static inline void fr_value_box_init(fr_value_box_t *box, fr_type_t type, + fr_dict_attr_t const *enumv, bool tainted) +{ + box->type = type; + box->enumv = enumv; + box->tainted = tainted; + box->next = NULL; + + memset(&box->datum, 0, sizeof(box->datum)); +} + +/** Allocate a value box of a specific type + * + * Allocates memory for the box, and sets the length of the value + * for fixed length types. + * + * @param[in] ctx to allocate the value_box in. + * @param[in] type of value. + * @param[in] enumv Enumeration values. + * @param[in] tainted Whether data will come from an untrusted source. + * @return + * - A new fr_value_box_t. + * - NULL on error. + */ +static inline fr_value_box_t *fr_value_box_alloc(TALLOC_CTX *ctx, fr_type_t type, + fr_dict_attr_t const *enumv, bool tainted) +{ + fr_value_box_t *value; + + value = talloc_zero(ctx, fr_value_box_t); + if (!value) return NULL; + + fr_value_box_init(value, type, enumv, tainted); + + return value; +} + +/** Box an ethernet value (6 bytes, network byte order) + * + * @param[in] dst Where to copy the ethernet address to. + * @param[in] enumv Enumeration values. + * @param[in] src The ethernet address. + * @param[in] tainted Whether data will come from an untrusted source. + * @return 0 (always successful). + */ +static inline int fr_value_box_ethernet_addr(fr_value_box_t *dst, fr_dict_attr_t const *enumv, + uint8_t const src[6], bool tainted) +{ + fr_value_box_init(dst, FR_TYPE_ETHERNET, enumv, tainted); + memcpy(dst->vb_ether, src, sizeof(dst->vb_ether)); + return 0; +} + +#define FR_VALUE_BOX(_ctype, _field, _type) \ +static inline int fr_value_box_##_field(fr_value_box_t *dst, fr_dict_attr_t const *enumv, _ctype value, bool tainted) { \ + fr_value_box_init(dst, _type, enumv, tainted); \ dst->vb_##_field = value; \ - dst->enumv = enumv; \ - dst->tainted = tainted; \ - dst->next = NULL; \ return 0; \ } -FR_VALUE_BOX_FROM(uint8_t, uint8, FR_TYPE_UINT8) -FR_VALUE_BOX_FROM(uint16_t, uint16, FR_TYPE_UINT16); -FR_VALUE_BOX_FROM(uint32_t, uint32, FR_TYPE_UINT32); -FR_VALUE_BOX_FROM(uint64_t, uint64, FR_TYPE_UINT64); +FR_VALUE_BOX(uint8_t, uint8, FR_TYPE_UINT8) +FR_VALUE_BOX(uint16_t, uint16, FR_TYPE_UINT16); +FR_VALUE_BOX(uint32_t, uint32, FR_TYPE_UINT32); +FR_VALUE_BOX(uint64_t, uint64, FR_TYPE_UINT64); -FR_VALUE_BOX_FROM(int8_t, int8, FR_TYPE_INT8); -FR_VALUE_BOX_FROM(int16_t, int16, FR_TYPE_INT16); -FR_VALUE_BOX_FROM(int32_t, int32, FR_TYPE_INT32); -FR_VALUE_BOX_FROM(int64_t, int64, FR_TYPE_INT64); +FR_VALUE_BOX(int8_t, int8, FR_TYPE_INT8); +FR_VALUE_BOX(int16_t, int16, FR_TYPE_INT16); +FR_VALUE_BOX(int32_t, int32, FR_TYPE_INT32); +FR_VALUE_BOX(int64_t, int64, FR_TYPE_INT64); -FR_VALUE_BOX_FROM(float, float32, FR_TYPE_FLOAT32); -FR_VALUE_BOX_FROM(double, float64, FR_TYPE_FLOAT64); +FR_VALUE_BOX(float, float32, FR_TYPE_FLOAT32); +FR_VALUE_BOX(double, float64, FR_TYPE_FLOAT64); -FR_VALUE_BOX_FROM(uint64_t, date, FR_TYPE_DATE); -FR_VALUE_BOX_FROM(uint64_t, date_milliseconds, FR_TYPE_DATE_MILLISECONDS); -FR_VALUE_BOX_FROM(uint64_t, date_microseconds, FR_TYPE_DATE_MICROSECONDS); -FR_VALUE_BOX_FROM(uint64_t, date_nanoseconds, FR_TYPE_DATE_NANOSECONDS); +FR_VALUE_BOX(uint64_t, date, FR_TYPE_DATE); +FR_VALUE_BOX(uint64_t, date_milliseconds, FR_TYPE_DATE_MILLISECONDS); +FR_VALUE_BOX(uint64_t, date_microseconds, FR_TYPE_DATE_MICROSECONDS); +FR_VALUE_BOX(uint64_t, date_nanoseconds, FR_TYPE_DATE_NANOSECONDS); -FR_VALUE_BOX_FROM(size_t, size, FR_TYPE_SIZE); -FR_VALUE_BOX_FROM(struct timeval, timeval, FR_TYPE_TIMEVAL); +FR_VALUE_BOX(size_t, size, FR_TYPE_SIZE); /** Automagically fill in a box, determining the value type from the type of the C variable * @@ -251,35 +312,101 @@ FR_VALUE_BOX_FROM(struct timeval, timeval, FR_TYPE_TIMEVAL); * * @param[in] _box to assign value to. * @param[in] _var C variable to assign value from. + * @param[in] _tainted Whether the value came from an untrusted source. */ -#define fr_box_from_cvar_shallow(_box, _var) \ +#define fr_value_box_shallow(_box, _var, _tainted) \ _Generic((_var), \ - char * : fr_value_box_strdup_buffer_shallow(_box, NULL, (_var), false), \ - char const * : fr_value_box_strdup_buffer_shallow(_box, NULL, (_var), false), \ - uint8_t * : fr_value_box_memdup_buffer_shallow(_box, NULL, (_var), false), \ - uint8_t const * : fr_value_box_memdup_buffer_shallow(_box, NULL, (_var), false), \ - fr_ipaddr_t : fr_value_box_from_ipaddr(_box, NULL, &(_var), false), \ - fr_ipaddr_t * : fr_value_box_from_ipaddr(_box, NULL, (_var), false), \ - uint8_t : fr_value_box_from_uint8(_box, NULL, (_var), false), \ - uint16_t : fr_value_box_from_uint16(_box, NULL, (_var), false), \ - uint32_t : fr_value_box_from_uint32(_box, NULL, (_var), false), \ - uint64_t : fr_value_box_from_uint64(_box, NULL, (_var), false), \ - int8_t : fr_value_box_from_int8(_box, NULL, (_var), false), \ - int16_t : fr_value_box_from_int16(_box, NULL, (_var), false), \ - int32_t : fr_value_box_from_int32(_box, NULL, (_var), false), \ - int64_t : fr_value_box_from_int64(_box, NULL, (_var), false), \ - float : fr_value_box_from_float32(_box, NULL, (_var), false), \ - double : fr_value_box_from_float64(_box, NULL, (_var), false), \ - size_t : fr_value_box_from_size(_box, NULL, (_var), false), \ - struct timeval : fr_value_box_from_timeval(_box, NULL, (_var), false) \ -) + fr_ipaddr_t * : fr_value_box_ipaddr, \ + uint8_t : fr_value_box_uint8, \ + uint16_t : fr_value_box_uint16, \ + uint32_t : fr_value_box_uint32, \ + uint64_t : fr_value_box_uint64, \ + int8_t : fr_value_box_int8, \ + int16_t : fr_value_box_int16, \ + int32_t : fr_value_box_int32, \ + int64_t : fr_value_box_int64, \ + float : fr_value_box_float32, \ + double : fr_value_box_float64, \ + size_t : fr_value_box_size \ +)(_box, NULL, _var, _tainted) + +/** Unbox an ethernet value (6 bytes, network byte order) + * + * @param[in] dst Where to copy the ethernet address to. + * @param[in] src Where to copy the ethernet address from. + * @return + * - 0 on success. + * - -1 on type mismatch. + */ +static inline int fr_value_unbox_ethernet_addr(uint8_t dst[6], fr_value_box_t *src) +{ + if (unlikely(src->type != FR_TYPE_ETHERNET)) { \ + fr_strerror_printf("Unboxing failed. Needed type %s, had type %s", + fr_int2str(dict_attr_types, FR_TYPE_ETHERNET, "?Unknown?"), + fr_int2str(dict_attr_types, src->type, "?Unknown?")); + return -1; \ + } + memcpy(dst, src->vb_ether, sizeof(src->vb_ether)); /* Must be src, dst is a pointer */ + return 0; +} + +#define FR_VALUE_UNBOX(_ctype, _field, _type) \ +static inline int fr_value_unbox_##_field(_ctype *var, fr_value_box_t const *src) { \ + if (unlikely(src->type != _type)) { \ + fr_strerror_printf("Unboxing failed. Needed type %s, had type %s", \ + fr_int2str(dict_attr_types, _type, "?Unknown?"), \ + fr_int2str(dict_attr_types, src->type, "?Unknown?")); \ + return -1; \ + } \ + *var = src->vb_##_field; \ + return 0; \ +} + +FR_VALUE_UNBOX(uint8_t, uint8, FR_TYPE_UINT8) +FR_VALUE_UNBOX(uint16_t, uint16, FR_TYPE_UINT16); +FR_VALUE_UNBOX(uint32_t, uint32, FR_TYPE_UINT32); +FR_VALUE_UNBOX(uint64_t, uint64, FR_TYPE_UINT64); + +FR_VALUE_UNBOX(int8_t, int8, FR_TYPE_INT8); +FR_VALUE_UNBOX(int16_t, int16, FR_TYPE_INT16); +FR_VALUE_UNBOX(int32_t, int32, FR_TYPE_INT32); +FR_VALUE_UNBOX(int64_t, int64, FR_TYPE_INT64); + +FR_VALUE_UNBOX(float, float32, FR_TYPE_FLOAT32); +FR_VALUE_UNBOX(double, float64, FR_TYPE_FLOAT64); + +FR_VALUE_UNBOX(uint64_t, date, FR_TYPE_DATE); +FR_VALUE_UNBOX(uint64_t, date_milliseconds, FR_TYPE_DATE_MILLISECONDS); +FR_VALUE_UNBOX(uint64_t, date_microseconds, FR_TYPE_DATE_MICROSECONDS); +FR_VALUE_UNBOX(uint64_t, date_nanoseconds, FR_TYPE_DATE_NANOSECONDS); + +FR_VALUE_UNBOX(size_t, size, FR_TYPE_SIZE); + +/** Unbox simple types peforming type checks + * + * @param[out] _var to write to. + * @param[in] _box to unbox. + */ +#define fr_value_unbox_shallow(_var, _box) \ +_Generic((_var), \ + uint8_t * : fr_value_unbox_uint8, \ + uint16_t * : fr_value_unbox_uint16, \ + uint32_t * : fr_value_unbox_uint32, \ + uint64_t * : fr_value_unbox_uint64, \ + int8_t * : fr_value_unbox_int8, \ + int16_t * : fr_value_unbox_int16, \ + int32_t * : fr_value_unbox_int32, \ + int64_t * : fr_value_unbox_int64, \ + float * : fr_value_unbox_float32, \ + double * : fr_value_unbox_float64, \ + size_t * : fr_value_unbox_size \ +)(_var, _box) + /* @} **/ /* - * Allocation + * Allocation - init/alloc use static functions (above) */ -fr_value_box_t *fr_value_box_alloc(TALLOC_CTX *ctx, fr_type_t type); - void fr_value_box_clear(fr_value_box_t *data); /* @@ -308,9 +435,11 @@ int fr_value_box_cast(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, fr_value_box_t const *src); -int fr_value_box_from_ipaddr(fr_value_box_t *dst, fr_dict_attr_t const *enumv, +int fr_value_box_ipaddr(fr_value_box_t *dst, fr_dict_attr_t const *enumv, fr_ipaddr_t const *ipaddr, bool tainted); +int fr_value_unbox_ipaddr(fr_ipaddr_t *dst, fr_value_box_t *src); + /* * Assignment */ @@ -324,7 +453,7 @@ int fr_value_box_bstrndup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t char const *src, size_t len, bool tainted); int fr_value_box_strdup_buffer(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted); -int fr_value_box_strsteal(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, +int fr_value_box_from_strsteal(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char *src, bool tainted); int fr_value_box_strdup_shallow(fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted); diff --git a/src/lib/util/value.c b/src/lib/util/value.c index 41b6f9fa4e4..a1a269815e2 100644 --- a/src/lib/util/value.c +++ b/src/lib/util/value.c @@ -215,28 +215,6 @@ size_t const fr_value_box_offsets[] = { [FR_TYPE_MAX] = 0 //!< Ensure array covers all types. }; -/** Allocate a value box of a specific type - * - * Allocates memory for the box, and sets the length of the value - * for fixed length types. - * - * @param[in] ctx to allocate the value_box in. - * @param[in] type of value. - * @return - * - A new fr_value_box_t. - * - NULL on error. - */ -fr_value_box_t *fr_value_box_alloc(TALLOC_CTX *ctx, fr_type_t type) -{ - fr_value_box_t *value; - - value = talloc_zero(ctx, fr_value_box_t); - if (!value) return NULL; - value->type = type; - - return value; -} - /** Clear/free any existing value * * @note Do not use on uninitialised memory. @@ -2178,15 +2156,17 @@ int fr_value_box_cast(TALLOC_CTX *ctx, fr_value_box_t *dst, * - 0 on success. * - -1 on failure. */ -int fr_value_box_from_ipaddr(fr_value_box_t *dst, fr_dict_attr_t const *enumv, fr_ipaddr_t const *ipaddr, bool tainted) +int fr_value_box_ipaddr(fr_value_box_t *dst, fr_dict_attr_t const *enumv, fr_ipaddr_t const *ipaddr, bool tainted) { + fr_type_t type; + switch (ipaddr->af) { case AF_INET: - dst->type = (fr_ipaddr_is_prefix(ipaddr) == 1) ? FR_TYPE_IPV4_PREFIX : FR_TYPE_IPV4_ADDR; + type = (fr_ipaddr_is_prefix(ipaddr) == 1) ? FR_TYPE_IPV4_PREFIX : FR_TYPE_IPV4_ADDR; break; case AF_INET6: - dst->type = (fr_ipaddr_is_prefix(ipaddr) == 1) ? FR_TYPE_IPV6_PREFIX : FR_TYPE_IPV6_ADDR; + type = (fr_ipaddr_is_prefix(ipaddr) == 1) ? FR_TYPE_IPV6_PREFIX : FR_TYPE_IPV6_ADDR; break; default: @@ -2194,11 +2174,33 @@ int fr_value_box_from_ipaddr(fr_value_box_t *dst, fr_dict_attr_t const *enumv, f return -1; } + fr_value_box_init(dst, type, enumv, tainted); memcpy(&dst->vb_ip, ipaddr, sizeof(dst->vb_ip)); - dst->enumv = enumv; - dst->tainted = tainted; - dst->next = NULL; + return 0; +} + +/** Unbox an IP address performing a type check + * + * @param[out] dst Where to copy the IP address to. + * @param[in] src Where to copy the IP address from. + * @return + * - 0 on success. + * - -1 on type mismatch. + */ +int fr_value_unbox_ipaddr(fr_ipaddr_t *dst, fr_value_box_t *src) +{ + switch (src->type) { + case FR_TYPE_IP: + break; + + default: + fr_strerror_printf("Unboxing failed. Needed IPv4/6 addr/prefix, had type %s", + fr_int2str(dict_attr_types, src->type, "?Unknown?")); + return -1; + } + + memcpy(dst, &src->vb_ip, sizeof(*dst)); return 0; } @@ -2453,7 +2455,7 @@ int fr_value_box_strdup_buffer(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_att * - 0 on success. * - -1 on failure. */ -int fr_value_box_strsteal(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, +int fr_value_box_from_strsteal(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char *src, bool tainted) { size_t len;