From: Arran Cudbard-Bell Date: Wed, 6 Dec 2023 23:19:45 +0000 (-0600) Subject: Add utility function to allow dictionaries to be dynamically autoloaded X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ab4bc0467a65cac4382903a4bf435d3d339ddaea;p=thirdparty%2Ffreeradius-server.git Add utility function to allow dictionaries to be dynamically autoloaded --- diff --git a/src/lib/util/dict.h b/src/lib/util/dict.h index 9a135910957..c31ebf439fe 100644 --- a/src/lib/util/dict.h +++ b/src/lib/util/dict.h @@ -66,6 +66,8 @@ typedef struct value_box_s fr_value_box_t; # define DA_VERIFY(_x) fr_cond_assert(_x) #endif +typedef struct fr_dict_autoload_talloc_s fr_dict_autoload_talloc_t; + /** Values of the encryption flags */ typedef struct { @@ -617,6 +619,9 @@ int _fr_dict_autoload(fr_dict_autoload_t const *to_load, char const *dependent #define fr_dict_autofree(_to_free) _fr_dict_autofree(_to_free, __FILE__) int _fr_dict_autofree(fr_dict_autoload_t const *to_free, char const *dependent); +#define fr_dict_autoload_talloc(_ctx, _dict_out, _proto) _fr_dict_autoload_talloc(_ctx, _dict_out, _proto, __FILE__) +fr_dict_autoload_talloc_t *_fr_dict_autoload_talloc(TALLOC_CTX *ctx, fr_dict_t const **out, char const *proto, char const *dependent); + int fr_dl_dict_enum_autoload(dl_t const *module, void *symbol, void *user_ctx); int fr_dl_dict_attr_autoload(dl_t const *module, void *symbol, void *user_ctx); diff --git a/src/lib/util/dict_util.c b/src/lib/util/dict_util.c index ec7ca83d6d8..32392626c32 100644 --- a/src/lib/util/dict_util.c +++ b/src/lib/util/dict_util.c @@ -3737,6 +3737,68 @@ int _fr_dict_autofree(fr_dict_autoload_t const *to_free, char const *dependent) return 0; } +/** Structure used to managed the lifetime of a dictionary + * + * This should only be used when dictionaries are being dynamically loaded during + * compilation. It should not be used to load dictionaries at runtime, or if + * modules need to load dicitonaries (use static fr_dict_autoload_t defs). + + */ +struct fr_dict_autoload_talloc_s { + fr_dict_autoload_t load[2]; //!< Autoloader def. + char const *dependent; //!< Dependent that loaded the dictionary. +}; + +/** Talloc destructor to automatically free dictionaries + * + * @param[in] to_free dictionary autoloader definition describing the dictionary to free. + */ +static int _fr_dict_autoload_talloc_free(fr_dict_autoload_talloc_t const *to_free) +{ + return _fr_dict_autofree(to_free->load, to_free->dependent); +} + +/** Autoload a dictionary and bind the lifetime to a talloc chunk + * + * Mainly useful for resolving "forward" references from unlang immediately. + * + * @note If the talloc chunk is freed it does not mean the dictionary will + * be immediately freeed. It will be freed when all other references + * to the dictionary are gone. + * + * @parma[in] ctx to bind the dictionary lifetime to. + * @parma[in] proto to load. + * @param[in] dependent to register this reference to. Will be dupd. + */ +fr_dict_autoload_talloc_t *_fr_dict_autoload_talloc(TALLOC_CTX *ctx, fr_dict_t const **out, char const *proto, char const *dependent) +{ + fr_dict_autoload_talloc_t *dict_ref; + int ret; + + dict_ref = talloc(ctx, fr_dict_autoload_talloc_t); + if (unlikely(dict_ref == NULL)) { + oom: + fr_strerror_const("Out of memory"); + return NULL; + } + + dict_ref->load[0] = (fr_dict_autoload_t){ .proto = proto, .out = out}; + dict_ref->load[1] = (fr_dict_autoload_t){ NULL }; + dict_ref->dependent = talloc_strdup(dict_ref, dependent); + if (unlikely(dict_ref->dependent == NULL)) { + talloc_free(dict_ref); + goto oom; + } + + ret = _fr_dict_autoload(dict_ref->load, dependent); + if (ret < 0) { + talloc_free(dict_ref); + return NULL; + } + + return dict_ref; +} + /** Callback to automatically resolve enum values * * @param[in] module being loaded.