]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
add doxygen and more utility functions
authorAlan T. DeKok <aland@freeradius.org>
Wed, 14 Jan 2026 01:39:53 +0000 (20:39 -0500)
committerAlan T. DeKok <aland@freeradius.org>
Wed, 14 Jan 2026 01:44:14 +0000 (20:44 -0500)
src/lib/util/stats.c
src/lib/util/stats.h

index 24afdd2b470a5fb9a63583d74c43b71db417541a..9aa3c64e83f4569f6b5d9e3557fb0983559f9d72 100644 (file)
@@ -24,8 +24,6 @@ RCSID("$Id$")
 
 #include <freeradius-devel/util/stats.h>
 
-// convert a set of pairs to a struct
-
 /** Convert a statistics structure to #fr_pair_t
  *
  * @param[in] ctx      talloc ctx
@@ -106,14 +104,21 @@ int fr_stats_to_pairs(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_stats_instance_t
        return 0;
 }
 
-int fr_stats_from_pairs(TALLOC_CTX *ctx, fr_stats_instance_t *inst, fr_pair_list_t *in)
+
+/** Convert a statistics structure to #fr_pair_t
+ *
+ * @param[in] ctx      talloc ctx
+ * @param[out] inst    where the output pairs will be stored
+ * @param[in] list     pairs where we read the pairs from
+ */
+int fr_stats_from_pairs(TALLOC_CTX *ctx, fr_stats_instance_t *inst, fr_pair_list_t const *list)
 {
        size_t i;
        fr_stats_link_t const *def = inst->def;
        uint8_t *out = inst->stats;
        fr_pair_t const *parent, *vp;
 
-       parent = fr_pair_find_by_da(in, NULL, *(def->root_p));
+       parent = fr_pair_find_by_da(list, NULL, *(def->root_p));
        if (!parent) return -1;
 
        memset(out, 0, inst->def->size);
@@ -227,8 +232,13 @@ static int stats_merge_internal(fr_stats_link_t const *def, void *out, void cons
 
 /** Public API for merging two statistics structures
  *
+ * @param[out] out     where the merged stats are written to
+ * @param[in] in       source stats to merge into out
+ * @return
+ *     - 0 on success
+ *     - <0 on the two instances are not compatible.
  */
-int fr_stats_merge(fr_stats_instance_t *out, fr_stats_instance_t const *in)
+int fr_stats_merge_instance(fr_stats_instance_t *out, fr_stats_instance_t const *in)
 {
        if (out->def != in->def) {
                fr_strerror_printf("Cannot merge stats into structure %s from different structure %s",
@@ -239,13 +249,76 @@ int fr_stats_merge(fr_stats_instance_t *out, fr_stats_instance_t const *in)
        return stats_merge_internal(out->def, out->stats, in->stats);
 }
 
+/** Public API for merging two value-boxes based on their enums
+ *
+ * @param[in,out] dst  where the merged stats are written to
+ * @param[in] src      source stats to merge into dst
+ * @return
+ *     - 0 on success
+ *     - <0 on the two boxes are not compatible, or we cannot merge the given data type
+ */
+int fr_stats_merge_value_box(fr_value_box_t *dst, fr_value_box_t const *src)
+{
+       if (dst->type != src->type) {
+               fr_strerror_const("Cannot merge two different data types");
+               return -1;
+       }
+
+       if (dst->enumv != src->enumv) {
+               fr_strerror_const("Cannot merge two different fields");
+               return -1;
+       }
+
+       if (!dst->enumv) {
+               fr_strerror_const("Unable to determine how to merge the fields");
+               return -1;
+       }
+
+       /*
+        *      @todo - distinguish counter from gauge.  This also means that we will need to update the
+        *      dictionary.stats to set the "counter" flag.
+        */
+
+       switch (dst->type) {
+       case FR_TYPE_UINT16:
+               dst->vb_uint16 += src->vb_uint16;
+               break;
+
+       case FR_TYPE_UINT32:
+               dst->vb_uint32 += src->vb_uint32;
+               break;
+
+       case FR_TYPE_UINT64:
+               dst->vb_uint64 += src->vb_uint64;
+               break;
+
+       default:
+               fr_strerror_const("Cannot merge non-integer data types");
+               return -1;
+       }
 
-void fr_stats_iter_init(fr_stats_instance_t const *in, fr_stats_iter_t *iter)
+       return 0;
+}
+
+
+/** Initialize an iterator over a structure
+ *
+ * @param[in] inst     data structure defining this instance of the statistics
+ * @param[out] iter    the initialized iterator
+ */
+void fr_stats_iter_init(fr_stats_instance_t const *inst, fr_stats_iter_t *iter)
 {
-       iter->inst = in;
+       iter->inst = inst;
        iter->current = 0;
 }
 
+/** Go to the next entry in a structure
+ *
+ * @param[in] iter     the iterator
+ * @return
+ *     - true for continue the iteration
+ *     - false for the iteration is done
+ */
 bool fr_stats_iter_next(fr_stats_iter_t *iter)
 {
        if (iter->current < iter->inst->def->num_elements) {
@@ -256,6 +329,17 @@ bool fr_stats_iter_next(fr_stats_iter_t *iter)
        return false;
 }
 
+
+/** Convert the statistic at an index to a value-box
+ *
+ * @param[in] ctx      the talloc context
+ * @param[out] out     the value-box to return
+ * @param[in] inst     data structure defining this instance of the statistics
+ * @param[in] index    the field index of the structure to use
+ * @return
+ *     - 0 for success, and *out is non-NULL
+ *     - <0 for error (memory allocation failed, index is invalid, etc), and *out is NULL
+ */
 int fr_stats_index_to_value_box(TALLOC_CTX *ctx, fr_value_box_t **out, fr_stats_instance_t const *inst, unsigned int index)
 {
        size_t len;
@@ -263,13 +347,17 @@ int fr_stats_index_to_value_box(TALLOC_CTX *ctx, fr_value_box_t **out, fr_stats_
        uint8_t const *field;
        fr_dict_attr_t const *da;
 
-       if (index >= inst->def->num_elements) return 0;
+       if (index >= inst->def->num_elements) {
+       fail:
+               *out = NULL;
+               return -1;
+       }
 
        da = *(inst->def->entry[index].da_p);
        fr_assert(da != NULL);
 
        box = fr_value_box_alloc(ctx, inst->def->entry[index].type, da);
-       if (!box) return -1;
+       if (!box) goto fail;
 
        field = ((uint8_t const *) inst->stats) + inst->def->entry[index].offset;
 
@@ -302,12 +390,13 @@ int fr_stats_index_to_value_box(TALLOC_CTX *ctx, fr_value_box_t **out, fr_stats_
        
        default:
                fr_strerror_printf("Unsupported data type '%s'", fr_type_to_str(box->type));
-               return -1;
+               goto fail_free;
        }
 
        if (fr_value_box_from_memory(box, box, box->type, da, field, len) < 0) {
+       fail_free:
                talloc_free(box);
-               return -1;
+               goto fail;
        }
 
        *out = box;
@@ -315,6 +404,15 @@ int fr_stats_index_to_value_box(TALLOC_CTX *ctx, fr_value_box_t **out, fr_stats_
 }
 
 
+/** Convert the statistic at the current iterator to a value-box
+ *
+ * @param[in] ctx      the talloc context
+ * @param[out] out     the value-box to return
+ * @param[in] iter     the iterator, which points to the current entry.
+ * @return
+ *     - 0 for success, and *out is non-NULL
+ *     - <0 for error (memory allocation failed, index is invalid, etc), and *out is NULL
+ */
 int fr_stats_iter_to_value_box(TALLOC_CTX *ctx, fr_value_box_t **out, fr_stats_iter_t *iter)
 {
        fr_assert(iter->inst);
@@ -322,3 +420,24 @@ int fr_stats_iter_to_value_box(TALLOC_CTX *ctx, fr_value_box_t **out, fr_stats_i
 
        return fr_stats_index_to_value_box(ctx, out, iter->inst, iter->current);
 }
+
+
+/** Convert the statistic of a given name to a value-box
+ *
+ * @param[in] ctx      the talloc context
+ * @param[out] out     the value-box to return
+ * @param[in] inst     data structure defining this instance of the statistics
+ * @param[in] name     the field name in the structure
+ * @return
+ *     - 0 for success, and *out is non-NULL
+ *     - <0 for error (memory allocation failed, name is invalid, etc), and *out is NULL
+ */
+int fr_stats_name_to_value_box(TALLOC_CTX *ctx, fr_value_box_t **out, fr_stats_instance_t const *inst, char const *name)
+{
+       fr_dict_attr_t const *da;
+
+       da = fr_dict_attr_by_name(NULL, *inst->def->root_p, name);
+       if (!da) return -1;
+
+       return fr_stats_index_to_value_box(ctx, out, inst, da->attr);
+}
index 6ee2d7cdd208adf8f505f88ad9c027670161b98c..c1e479c383495da6bd4f59009d93c09298a87de0 100644 (file)
@@ -140,13 +140,17 @@ typedef struct {
 #define FR_STATS_FIELD(_var, _field) (_var)->stats.(_field)
 
 int    fr_stats_to_pairs(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_stats_instance_t const *in) CC_HINT(nonnull);
-int    fr_stats_from_pairs(TALLOC_CTX *ctx, fr_stats_instance_t *out, fr_pair_list_t *in) CC_HINT(nonnull);
-int    fr_stats_merge(fr_stats_instance_t *out, fr_stats_instance_t const *in) CC_HINT(nonnull);
+int    fr_stats_from_pairs(TALLOC_CTX *ctx, fr_stats_instance_t *out, fr_pair_list_t const *list) CC_HINT(nonnull);
+int    fr_stats_merge_instance(fr_stats_instance_t *out, fr_stats_instance_t const *in) CC_HINT(nonnull);
+int    fr_stats_merge_value_box(fr_value_box_t *dst, fr_value_box_t const *src) CC_HINT(nonnull);
 
 void   fr_stats_iter_init(fr_stats_instance_t const *in, fr_stats_iter_t *iter) CC_HINT(nonnull);
 bool   fr_stats_iter_next(fr_stats_iter_t *iter) CC_HINT(nonnull);
 int    fr_stats_iter_to_value_box(TALLOC_CTX *ctx, fr_value_box_t **out, fr_stats_iter_t *iter) CC_HINT(nonnull);
-int    fr_stats_index_to_value_box(TALLOC_CTX *ctx, fr_value_box_t **out, fr_stats_instance_t const *in, unsigned int index) CC_HINT(nonnull);
+int    fr_stats_index_to_value_box(TALLOC_CTX *ctx, fr_value_box_t **out,
+                                   fr_stats_instance_t const *in, unsigned int index) CC_HINT(nonnull);
+int    fr_stats_name_to_value_box(TALLOC_CTX *ctx, fr_value_box_t **out,
+                                  fr_stats_instance_t const *inst, char const *name) CC_HINT(nonnull);
 
 
 #ifdef __cplusplus