Collapsing a completely useless layer of abstraction and making everything significantly easier to understand and use.
fr_listen_t *child; //!< child listener (app_io) for this socket
fr_io_client_t *client; //!< our local client (pending or connected).
fr_io_client_t *parent; //!< points to the parent client.
- dl_module_inst_t *dl_inst; //!< for submodule
+ module_instance_t *mi; //!< for submodule
bool dead; //!< roundabout way to get the network side to close a socket
bool paused; //!< event filter doesn't like resuming something that isn't paused
{
int ret;
fr_io_connection_t *connection;
- dl_module_inst_t *dl_inst = NULL;
+ module_instance_t *mi = NULL;
fr_listen_t *li;
fr_client_t *radclient;
*/
if (!nak) {
char *inst_name;
+ char const *transport_name = inst->submodule->module->exported->name;
if (inst->max_connections || client->radclient->limit.max_connections) {
uint32_t max_connections = inst->max_connections ? inst->max_connections : client->radclient->limit.max_connections;
if ((thread->num_connections + 1) >= max_connections) {
DEBUG("proto_%s - Ignoring connection from client %s - 'max_connections' limit reached.",
inst->app->common.name, client->radclient->shortname);
- close_and_return:
if (fd >= 0) close(fd);
return NULL;
}
}
/*
- * FIXME - This is not at all thread safe
+ * FIXME - This should a 'sub' module list
*/
- inst_name = talloc_asprintf(NULL, "%s%"PRIu64, inst->transport, thread->client_id++);
- if (dl_module_instance(NULL, &dl_inst, inst->dl_inst,
- DL_MODULE_TYPE_SUBMODULE, inst->transport, inst_name) < 0) {
- talloc_free(inst_name);
- DEBUG("Failed to find proto_%s_%s", inst->app->common.name, inst->transport);
- goto close_and_return;
- }
- talloc_free(inst_name);
+ inst_name = talloc_asprintf(NULL, "%s%"PRIu64, transport_name, thread->client_id++);
+ mi = module_instance_alloc(inst->submodule->ml, inst->submodule, DL_MODULE_TYPE_SUBMODULE,
+ inst->submodule->module->exported->name, inst_name);
-/*
- if (dl_module_conf_parse(dl_inst, inst->server_cs) < 0) {
+ if (module_instance_conf_parse(mi, inst->server_cs) < 0) {
+ cf_log_perr(inst->server_cs, "Failed parsing module config");
goto cleanup;
}
-*/
- fr_assert(dl_inst != NULL);
+
+ /*
+ * FIXME - Instantiate the new module?!
+ */
+ talloc_free(inst_name);
+ fr_assert(mi != NULL);
} else {
- dl_inst = talloc_init_const("nak");
+ mi = talloc_init_const("nak");
}
- MEM(connection = talloc_zero(dl_inst, fr_io_connection_t));
+ MEM(connection = talloc_zero(mi, fr_io_connection_t));
MEM(connection->address = talloc_memdup(connection, address, sizeof(*address)));
(void) talloc_set_name_const(connection->address, "fr_io_address_t");
connection->parent = client;
- connection->dl_inst = dl_inst;
+ connection->mi = mi;
MEM(connection->client = talloc_named(NULL, sizeof(fr_io_client_t), "fr_io_client_t"));
memset(connection->client, 0, sizeof(*connection->client));
li->connected = true;
li->app_io = thread->child->app_io;
li->thread_instance = connection;
- li->app_io_instance = dl_inst->data;
+ li->app_io_instance = mi->data;
li->track_duplicates = thread->child->app_io->track_duplicates;
/*
&connection->address->socket.inet.src_ipaddr,
connection->address->socket.inet.src_port) < 0) {
DEBUG("proto_%s - Failed getting IP address", inst->app->common.name);
- talloc_free(dl_inst);
+ talloc_free(mi);
return NULL;
}
if (inst->app_io->open(connection->child) < 0) {
DEBUG("proto_%s - Failed opening connected socket.", inst->app->common.name);
- talloc_free(dl_inst);
+ talloc_free(mi);
return NULL;
}
cleanup:
if (fd >= 0) close(fd);
- talloc_free(dl_inst);
+ talloc_free(mi);
return NULL;
}
*/
if (radclient->use_connected && !inst->app_io->connection_set) {
DEBUG("proto_%s - cannot use connected sockets as underlying 'transport = %s' does not support it.",
- inst->app_io->common.name, inst->submodule->dl_inst->module->common->name);
+ inst->app_io->common.name, inst->submodule->module->exported->name);
goto error;
}
*/
fr_network_listen_delete(connection->nr, child);
- talloc_free(connection->dl_inst);
+ talloc_free(connection->mi);
return 0;
}
/*
* Find and bootstrap the application IO handler.
*/
- inst->app_io = (fr_app_io_t const *) inst->submodule->dl_inst->module->common;
+ inst->app_io = (fr_app_io_t const *) inst->submodule->module->exported;
- inst->app_io_conf = inst->submodule->dl_inst->conf;
- inst->app_io_instance = inst->submodule->dl_inst->data;
+ inst->app_io_conf = inst->submodule->conf;
+ inst->app_io_instance = inst->submodule->data;
/*
* If we're not tracking duplicates then we don't need a
}
}
- if (inst->app_io->common.bootstrap && (inst->app_io->common.bootstrap(MODULE_INST_CTX(inst->submodule->dl_inst)) < 0)) {
+ if (inst->app_io->common.bootstrap && (inst->app_io->common.bootstrap(MODULE_INST_CTX(inst->submodule)) < 0)) {
cf_log_err(inst->app_io_conf, "Bootstrap failed for proto_%s", inst->app_io->common.name);
return -1;
}
fr_assert(inst->app_io != NULL);
if (inst->app_io->common.instantiate &&
- (inst->app_io->common.instantiate(MODULE_INST_CTX(inst->submodule->dl_inst)) < 0)) {
+ (inst->app_io->common.instantiate(MODULE_INST_CTX(inst->submodule)) < 0)) {
cf_log_err(conf, "Instantiation failed for \"proto_%s\"", inst->app_io->common.name);
return -1;
}
* creates the listener, and adds it to the scheduler.
*/
typedef struct {
- dl_module_inst_t const *dl_inst; //!< our parent dl_inst
+ module_instance_t const *mi; //!< our parent mi
uint32_t max_connections; //!< maximum number of connections to allow
uint32_t max_clients; //!< maximum number of dynamic clients to allow
* Provides space to store instance data.
*/
struct dl_module_loader_s {
- pthread_mutex_t lock; //!<
+ pthread_mutex_t lock; //!< Protects the module tree when multiple threads are loading modules simultaneously.
fr_rb_tree_t *module_tree; //!< Module's dl handles.
- fr_rb_tree_t *inst_data_tree; //!< Module's instance data.
dl_loader_t *dl_loader; //!< A list of loaded libraries, and symbol to callback mappings.
};
static dl_module_loader_t *dl_module_loader;
-/** Make data to instance name resolution more efficient
- *
- */
-typedef struct {
- void *data; //!< Module's data.
- dl_module_inst_t *inst; //!< Instance wrapper struct.
-} dl_module_inst_cache_t;
-
-static _Thread_local dl_module_inst_cache_t dl_inst_cache;
-
/** Name prefixes matching the types of loadable module
*/
fr_table_num_sorted_t const dl_module_type_prefix[] = {
};
size_t dl_module_type_prefix_len = NUM_ELEMENTS(dl_module_type_prefix);
-static int8_t dl_module_inst_data_cmp(void const *one, void const *two)
-{
- dl_module_inst_t const *a = one, *b = two;
-
- fr_assert(a->data);
- fr_assert(b->data);
-
- return CMP(a->data, b->data);
-}
-
static int8_t dl_module_cmp(void const *one, void const *two)
{
dl_module_t const *a = one, *b = two;
*/
fr_strerror_clear();
- if (dl_module->common->onload) {
+ if (dl_module->exported->onload) {
int ret;
- ret = dl_module->common->onload();
+ ret = dl_module->exported->onload();
if (ret < 0) {
#ifndef NDEBUG
PERROR("Initialisation failed for module \"%s\" - onload() returned %i",
- dl_module->common->name, ret);
+ dl_module->exported->name, ret);
#else
PERROR("Initialisation failed for module \"%s\"", dl_module->common->name);
#endif
* common is NULL if we couldn't find the
* symbol and are erroring out.
*/
- if (dl_module->common && dl_module->common->unload) dl_module->common->unload();
+ if (dl_module->exported && dl_module->exported->unload) dl_module->exported->unload();
}
/** Check if the magic number in the module matches the one in the library
return 0;
}
-/** Return top root module, in a hierarchy of modules
- *
- */
-dl_module_inst_t const *dl_module_instance_root(dl_module_inst_t const *dl_inst)
-{
- if (!dl_inst) return NULL;
-
- while (dl_inst->parent) dl_inst = dl_inst->parent;
-
- return dl_inst;
-}
-
-/** Return the prefix string for the deepest module
- *
- * This is useful for submodules which don't have a prefix of their own.
- * In this case we need to use the prefix of the shallowest module, which
- * will be a proto or rlm module.
- *
- * @param[in] dl_inst Instance to get the prefix for.
- * @return The prefix string for the shallowest module.
- */
-char const *dl_module_instance_root_prefix_str(dl_module_inst_t const *dl_inst)
-{
- dl_module_inst_t const *root = dl_module_instance_root(dl_inst);
-
- return fr_table_str_by_value(dl_module_type_prefix, root->module->type, "<INVALID>");
-}
-
-/** Lookup a module's parent
- *
- */
-dl_module_inst_t const *dl_module_parent_instance(dl_module_inst_t const *child)
-{
- return child->parent;
-}
-
-/** Lookup a dl_module_inst_t via instance data
- *
- */
-dl_module_inst_t const *dl_module_instance_by_data(void const *data)
-{
- DL_INIT_CHECK;
-
- if (dl_inst_cache.data == data) return dl_inst_cache.inst;
-
- return fr_rb_find(dl_module_loader->inst_data_tree, &(dl_module_inst_t){ .data = UNCONST(void *, data) });
-}
-
-/** Lookup a dl_module_inst_t via a config section
- *
- */
-dl_module_inst_t const *dl_module_instance_by_cs(CONF_SECTION const *cs)
-{
- return cf_data_value(cf_data_find(cs, dl_module_inst_t, CF_IDENT_ANY));
-}
-
-/** Lookup instance name via instance data
- *
- */
-char const *dl_module_instance_name_by_data(void const *data)
-{
- dl_module_inst_t const *inst;
-
- inst = dl_module_instance_by_data(data);
- if (!inst) return NULL;
-
- return inst->name;
-}
-
-/** A convenience function for returning a parent's private data
- *
- * @param[in] data Private instance data for child.
- * @return
- * - Parent's private instance data.
- * - NULL if no parent
- */
-void *dl_module_parent_data_by_child_data(void const *data)
-{
- dl_module_inst_t const *dl_inst;
-
- DL_INIT_CHECK;
-
- dl_inst = dl_module_instance_by_data(data);
- if (!dl_inst) return NULL;
-
- if (!dl_inst->parent) return NULL;
-
- return dl_inst->parent->data;
-}
-
-/** Detach the shallowest parent first
- *
- */
-static void dl_module_detach_parent(dl_module_inst_t *dl_inst)
-{
- if (dl_inst->detached) return;
-
- if (dl_inst->parent) dl_module_detach_parent(UNCONST(dl_module_inst_t *, dl_inst->parent));
-
- if (dl_inst->module->common->detach) {
- dl_inst->module->common->detach(&(module_detach_ctx_t){ .inst = dl_inst });
- dl_inst->detached = true;
- }
-}
-
-static int _dl_module_instance_data_free(void *data)
-{
- dl_module_inst_t *dl_inst = UNCONST(dl_module_inst_t *, dl_module_instance_by_data(data));
-
- if (!dl_inst) {
- ERROR("Failed resolving data %p, to dl_module_inst_t, refusing to free", data);
- return -1;
- }
-
- /*
- * Ensure the shallowest parent module
- * gets detached first so that it can
- * still reach its children.
- */
- dl_module_detach_parent(dl_inst);
-
- return 0;
-}
-
-/** Allocate module instance data, and parse the module's configuration
- *
- * @param[in] dl_inst to allocate this instance data in.
- * @param[in] module to alloc instance data for.
- */
-static void dl_module_instance_data_alloc(dl_module_inst_t *dl_inst, dl_module_t const *module)
-{
- void *data;
-
- /*
- * If there is supposed to be instance data, allocate it now.
- *
- * If the structure is zero length then allocation will still
- * succeed, and will create a talloc chunk header.
- *
- * This is needed so we can resolve instance data back to
- * dl_module_inst_t/dl_module_t/dl_t.
- */
- MEM(data = talloc_zero_array(dl_inst, uint8_t, module->common->inst_size));
-
- if (!module->common->inst_type) {
- talloc_set_name(data, "%s_t", module->dl->name ? module->dl->name : "config");
- } else {
- talloc_set_name_const(data, module->common->inst_type);
- }
- dl_inst->data = data;
-
- /*
- * Must be done before setting the destructor to ensure the
- * destructor can find the dl_module_inst_t associated
- * with the data.
- */
- fr_assert(dl_module_loader != NULL);
- fr_rb_insert(dl_module_loader->inst_data_tree, dl_inst); /* Duplicates not possible */
-
- talloc_set_destructor(data, _dl_module_instance_data_free);
-}
-
/** Decrement the reference count of the dl, eventually freeing it
*
*/
if (dl_module->dl) {
if (DEBUG_ENABLED4) {
DEBUG4("%s unloaded. Handle address %p, symbol address %p", dl_module->dl->name,
- dl_module->dl->handle, dl_module->common);
+ dl_module->dl->handle, dl_module->exported);
} else {
DEBUG3("%s unloaded", dl_module->dl->name);
}
int dl_module_free(dl_module_t *dl_module)
{
int ret;
+ dl_module_loader_t *dl_module_l = dl_module->loader; /* Save this, as dl_module will be free'd */
- pthread_mutex_lock(&dl_module->loader->lock);
+ pthread_mutex_lock(&dl_module_l->lock);
ret = talloc_free(dl_module);
- pthread_mutex_unlock(&dl_module->loader->lock);
+ pthread_mutex_unlock(&dl_module_l->lock);
return ret;
}
module_name = talloc_typed_asprintf(NULL, "%s_%s_%s",
fr_table_str_by_value(dl_module_type_prefix,
parent->type, "<INVALID>"),
- parent->common->name, name);
+ parent->exported->name, name);
} else {
module_name = talloc_typed_asprintf(NULL, "%s_%s",
fr_table_str_by_value(dl_module_type_prefix, type, "<INVALID>"),
}
MEM(dl_module = talloc_zero(dl_module_loader, dl_module_t));
+ dl_module->name = talloc_strdup(dl_module, name);
dl_module->loader = dl_module_loader;
dl_module->parent = parent;
dl_module->type = type;
ERROR("Could not find \"%s\" symbol in module: %s", module_name, dlerror());
goto error;
}
- dl_module->common = common;
+ dl_module->exported = common;
/*
* Before doing anything else, check if it's sane.
return dl_module;
}
-/** Free a module instance, removing it from the instance tree
- *
- * Also decrements the reference count of the module potentially unloading it.
- *
- * @param[in] dl_inst to free.
- * @return 0.
- */
-static int _dl_module_instance_free(dl_module_inst_t *dl_inst)
-{
- /*
- * Ensure sane free order, and that all destructors
- * run before the .so/.dylib is unloaded.
- *
- * This *MUST* be done *BEFORE* decrementing the
- * reference count on the module.
- *
- * It also *MUST* be done before removing this struct
- * from the inst_data_tree, so the detach destructor
- * can find the dl_module_inst_t associated with
- * the opaque data.
- */
- talloc_free_children(dl_inst);
-
- /*
- * Remove this instance from the tracking tree.
- */
- fr_assert(dl_module_loader != NULL);
- fr_rb_delete(dl_module_loader->inst_data_tree, dl_inst);
-
- /*
- * Decrements the reference count. The module object
- * won't be unloaded until all instances of that module
- * have been destroyed.
- */
- dl_module_free(dl_inst->module);
-
- return 0;
-}
-
-/** Retrieve a public symbol from a module using dlsym
- *
- * Convenience function to lookup/return public symbols from modules loaded
- * with #dl_module_instance.
- *
- * @param[in] dl_inst Instance who's module we're looking for the symbol in.
- * @param[in] sym_name to lookup.
- * @return
- * - Pointer to the public data structure.
- * - NULL if no matching symbol was found.
- */
-void *dl_module_instance_symbol(dl_module_inst_t const *dl_inst, char const *sym_name)
-{
- if (!sym_name) return NULL;
-
- return dlsym(dl_inst->module->dl->handle, sym_name);
-}
-
-/** Load a module and parse its #CONF_SECTION in one operation
- *
- * When this instance is no longer needed, it should be freed with talloc_free().
- * When all instances of a particular module are unloaded, the dl handle will be closed,
- * unloading the module.
- *
- * @param[in] ctx to allocate structures in.
- * @param[out] out where to write our #dl_module_inst_t containing the module
- * handle and instance.
- * @param[in] parent of module instance.
- * @param[in] type of module to load.
- * @param[in] mod_name of the module to load .e.g. 'udp' for 'proto_radius_udp'
- * if the parent were 'proto_radius'.
- * @param[in] inst_name The name of the instance .e.g. 'sql_aws_dc01'
- *
- * @return
- * - 0 on success.
- * - -1 on failure.
- */
-int dl_module_instance(TALLOC_CTX *ctx, dl_module_inst_t **out,
- dl_module_inst_t const *parent,
- dl_module_type_t type, char const *mod_name, char const *inst_name)
-{
- dl_module_inst_t *dl_inst;
-
- DL_INIT_CHECK;
-
- MEM(dl_inst = talloc_zero(ctx, dl_module_inst_t));
-
- dl_inst->module = dl_module_alloc(parent ? parent->module : NULL, mod_name, type);
- if (!dl_inst->module) {
- talloc_free(dl_inst);
- return -1;
- }
- dl_inst->name = talloc_typed_strdup(dl_inst, inst_name);
-
- /*
- * ctx here is the main module's instance data
- */
- dl_module_instance_data_alloc(dl_inst, dl_inst->module);
- talloc_set_destructor(dl_inst, _dl_module_instance_free);
-
- dl_inst->parent = parent;
- *out = dl_inst;
-
- return 0;
-}
-
-/** Avoid boilerplate when setting the module instance name
- *
- */
-char const *dl_module_inst_name_from_conf(CONF_SECTION *conf)
-{
- char const *name2;
-
- name2 = cf_section_name2(conf);
- if (name2) return name2;
-
- return cf_section_name1(conf);
-}
-
-int dl_module_conf_parse(dl_module_inst_t *dl_inst, CONF_SECTION *conf)
-{
- /*
- * Associate the module instance with the conf section
- * *before* executing any parse rules that might need it.
- */
- cf_data_add(conf, dl_inst, dl_inst->module->dl->name, false);
- dl_inst->conf = conf;
-
- if (dl_inst->module->common->config && dl_inst->conf) {
- if ((cf_section_rules_push(dl_inst->conf, dl_inst->module->common->config)) < 0 ||
- (cf_section_parse(dl_inst->data, dl_inst->data, dl_inst->conf) < 0)) {
- cf_log_err(dl_inst->conf, "Failed evaluating configuration for module \"%s\"",
- dl_inst->module->dl->name);
- return -1;
- }
- }
-
- return 0;
-}
-
static int _dl_module_loader_free(dl_module_loader_t *dl_module_l)
{
int ret = 0;
fr_assert_msg(pthread_mutex_trylock(&dl_module_l->lock) == 0,
"dl_module_loader->lock held when attempting to free dL_module_loader_t");
- if (fr_rb_num_elements(dl_module_l->inst_data_tree) > 0) {
+ if (fr_rb_num_elements(dl_module_l->module_tree) > 0) {
#ifndef NDEBUG
fr_rb_iter_inorder_t iter;
- void *data;
+ void *data;
- WARN("Refusing to cleanup dl loader, the following module instances are still in use:");
- for (data = fr_rb_iter_init_inorder(&iter, dl_module_l->inst_data_tree);
+ WARN("Refusing to cleanup dl loader, the following modules are still in use:");
+ for (data = fr_rb_iter_init_inorder(&iter, dl_module_l->module_tree);
data;
data = fr_rb_iter_next_inorder(&iter)) {
- dl_module_inst_t *dl_inst = talloc_get_type_abort(data, dl_module_inst_t);
+ dl_module_t *module = talloc_get_type_abort(data, dl_module_t);
- WARN(" %s (%s)", dl_inst->module->dl->name, dl_inst->name);
+ WARN(" %s", module->exported->name);
}
#endif
ret = -1;
}
if (lib_dir) dl_search_path_prepend(dl_module_loader->dl_loader, lib_dir);
- dl_module_loader->inst_data_tree = fr_rb_talloc_alloc(dl_module_loader, dl_module_inst_t,
- dl_module_inst_data_cmp, NULL);
- if (!dl_module_loader->inst_data_tree) {
- ERROR("Failed initialising dl->inst_data_tree");
- goto error;
- }
-
dl_module_loader->module_tree = fr_rb_talloc_alloc(dl_module_loader, dl_module_t,
dl_module_cmp, NULL);
- if (!dl_module_loader->inst_data_tree) {
+ if (!dl_module_loader->module_tree) {
ERROR("Failed initialising dl->module_tree");
goto error;
}
# define DL_EXTENSION ".so"
#endif
-typedef struct dl_module_instance_s dl_module_inst_t;
-
/** Stop people using different module/library/server versions together
*
*/
typedef struct dl_module_loader_s dl_module_loader_t;
-typedef struct {
- dl_module_inst_t const *inst;
-} module_detach_ctx_t;
-
-/** Module detach callback
- *
- * Is called just before the server exits, and after re-instantiation on HUP,
- * to free the old module instance.
- *
- * Detach should close all handles associated with the module instance, and
- * free any memory allocated during instantiate.
- *
- * @param[in] inst to free.
- * @return
- * - 0 on success.
- * - -1 if detach failed.
- */
-typedef int (*module_detach_t)(module_detach_ctx_t const *inst);
-
/** Callback to call when a module is first loaded
*
*/
typedef int (*dl_module_onload_t)(void);
-
/** Callback when a module is destroyed
*
*/
/** Common fields for the interface struct modules export
*
+ * These are just enough for the loader to be able to load and unload the module.
*/
#define DL_MODULE_COMMON \
struct { \
uint64_t magic; \
char const *name; \
- size_t inst_size; \
- char const *inst_type; \
- conf_parser_t const *config; \
dl_module_onload_t onload; \
dl_module_unload_t unload; \
- module_detach_t detach; \
}
/** Fields common to all types of loadable modules
*/
typedef struct dl_module_s dl_module_t;
struct dl_module_s {
+ char const * _CONST name; //!< Name of the module. The name passed to dl_module_alloc.
+
dl_module_loader_t * _CONST loader; //!< Loader that owns this dl.
dl_t * _CONST dl; //!< Dynamic loader handle.
dl_module_type_t _CONST type; //!< of this module.
- dl_module_common_t const * _CONST common; //!< Symbol exported by the module, containing its public
+ dl_module_common_t const * _CONST exported; //!< Symbol exported by the module, containing its public
//!< functions, name and behaviour control flags.
CONF_SECTION * _CONST conf; //!< The module's global configuration
bool _CONST in_tree;
};
-/** A module/inst tuple
- *
- * Used to pass data back from dl_module_instance_parse_func
- */
-struct dl_module_instance_s {
- char const * _CONST name; //!< Instance name.
- dl_module_t * _CONST module; //!< Module
- void * _CONST data; //!< Module instance's parsed configuration.
- CONF_SECTION * _CONST conf; //!< Module's instance configuration.
- dl_module_inst_t const * _CONST parent; //!< Parent module's instance (if any).
- bool _CONST detached; //!< Whether the detach function has been called.
-};
-
extern fr_table_num_sorted_t const dl_module_type_prefix[];
extern size_t dl_module_type_prefix_len;
dl_module_t *dl_module_alloc(dl_module_t const *parent, char const *name, dl_module_type_t type);
-dl_module_inst_t const *dl_module_instance_root(dl_module_inst_t const *dl_inst);
-
-char const *dl_module_instance_root_prefix_str(dl_module_inst_t const *dl_inst);
-
-dl_module_inst_t const *dl_module_parent_instance(dl_module_inst_t const *child);
-
-dl_module_inst_t const *dl_module_instance_by_data(void const *data);
-
-dl_module_inst_t const *dl_module_instance_by_cs(CONF_SECTION const *cs);
-
-char const *dl_module_instance_name_by_data(void const *data);
-
-void *dl_module_parent_data_by_child_data(void const *data);
-
-void *dl_module_instance_symbol(dl_module_inst_t const *instance, char const *sym_name);
-
-int dl_module_instance(TALLOC_CTX *ctx, dl_module_inst_t **out,
- dl_module_inst_t const *parent,
- dl_module_type_t type, char const *name, char const *inst_name);
-
-char const *dl_module_inst_name_from_conf(CONF_SECTION *conf);
-
-int dl_module_conf_parse(dl_module_inst_t *dl_inst, CONF_SECTION *conf);
-
char const *dl_module_search_path(void);
dl_loader_t *dl_loader_from_module_loader(dl_module_loader_t *dl_module_loader);
* @brief Defines functions for module (re-)initialisation.
*
* @copyright 2003,2006,2016 The FreeRADIUS server project
- * @copyright 2016 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
+ * @copyright 2016,2024 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
* @copyright 2000 Alan DeKok (aland@freeradius.org)
* @copyright 2000 Alan Curry (pacman@world.std.com)
*/
+#include "lib/util/talloc.h"
RCSID("$Id$")
#include <freeradius-devel/server/base.h>
{
module_instance_t *mi = ctx;
- fr_assert(mi->dl_inst->conf != NULL);
+ fr_assert(mi->conf != NULL);
- (void) cf_section_write(fp, mi->dl_inst->conf, 0);
+ (void) cf_section_write(fp, mi->conf, 0);
return 0;
}
return 0;
}
+/** Return the prefix string for the deepest module
+ *
+ * This is useful for submodules which don't have a prefix of their own.
+ * In this case we need to use the prefix of the shallowest module, which
+ * will be a proto or rlm module.
+ *
+ * @param[in] mi Instance to get the prefix for.
+ * @return The prefix string for the shallowest module.
+ */
+char const *module_instance_root_prefix_str(module_instance_t const *mi)
+{
+ module_instance_t const *root = module_instance_root(mi);
+
+ return fr_table_str_by_value(dl_module_type_prefix, root->module->type, "<INVALID>");
+}
+
+/** Detach the shallowest parent first
+ *
+ */
+static void module_detach_parent(module_instance_t *mi)
+{
+ if (mi->detached) return;
+
+ if (mi->parent) module_detach_parent(UNCONST(module_instance_t *, mi->parent));
+
+ if (mi->exported->detach) {
+ mi->exported->detach(&(module_detach_ctx_t){ .inst = mi });
+ mi->detached = true;
+ }
+}
+
+/** Allocate module instance data
+ *
+ * @param[in] mi to allocate instance data for
+ */
+static inline CC_HINT(always_inline)
+void module_instance_data_alloc(module_instance_t *mi)
+{
+ dl_module_t const *module = mi->module;
+ void *data;
+
+ /*
+ * If there is supposed to be instance data, allocate it now.
+ *
+ * If the structure is zero length then allocation will still
+ * succeed, and will create a talloc chunk header.
+ *
+ * This is needed so we can resolve instance data back to
+ * module_instance_t/dl_module_t/dl_t.
+ */
+ MEM(data = talloc_zero_array(mi, uint8_t, mi->exported->inst_size));
+ if (!mi->exported->inst_type) {
+ talloc_set_name(data, "%s_t", module->dl->name ? module->dl->name : "config");
+ } else {
+ talloc_set_name_const(data, mi->exported->inst_type);
+ }
+ mi->data = data;
+}
+
+/** Avoid boilerplate when setting the module instance name
+ *
+ */
+char const *module_instance_name_from_conf(CONF_SECTION *conf)
+{
+ char const *name2;
+
+ name2 = cf_section_name2(conf);
+ if (name2) return name2;
+
+ return cf_section_name1(conf);
+}
+
+/** Covert a CONF_SECTION into parsed module instance data
+ *
+ */
+int module_instance_conf_parse(module_instance_t *mi, CONF_SECTION *conf)
+{
+ /*
+ * Associate the module instance with the conf section
+ * *before* executing any parse rules that might need it.
+ */
+ cf_data_add(conf, mi, mi->module->dl->name, false);
+ mi->conf = conf;
+
+ if (mi->exported->config && mi->conf) {
+ if ((cf_section_rules_push(mi->conf, mi->exported->config)) < 0 ||
+ (cf_section_parse(mi->data, mi->data, mi->conf) < 0)) {
+ cf_log_err(mi->conf, "Failed evaluating configuration for module \"%s\"",
+ mi->module->dl->name);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
/** Sort module instance data first by list then by number
*
* The module's position in the global instance heap informs of us
{
module_instance_t const *a = one;
module_instance_t const *b = two;
- dl_module_inst_t const *dl_inst;
+ module_instance_t const *mi;
int a_depth = 0, b_depth = 0;
int ret;
* at the shallowest node, and finish with
* the deepest child.
*/
- for (dl_inst = a->dl_inst; dl_inst; dl_inst = dl_inst->parent) a_depth++;
- for (dl_inst = b->dl_inst; dl_inst; dl_inst = dl_inst->parent) b_depth++;
+ for (mi = a; mi; mi = mi->parent) a_depth++;
+ for (mi = b; mi; mi = mi->parent) b_depth++;
ret = CMP(a_depth, b_depth);
if (ret != 0) return ret;
/*
- * This happens, as dl_inst is is used in
+ * This happens, as mi is is used in
* as the loop condition above.
*/
#ifdef STATIC_ANALYZER
- if (!fr_cond_assert(a->dl_inst)) return +1;
- if (!fr_cond_assert(b->dl_inst)) return -1;
+ if (!fr_cond_assert(a)) return +1;
+ if (!fr_cond_assert(b)) return -1;
#endif
- ret = CMP(a->dl_inst->parent, b->dl_inst->parent);
+ ret = CMP(a->parent, b->parent);
if (ret != 0) return ret;
ret = strcmp(a->name, b->name);
*/
static int8_t module_instance_data_cmp(void const *one, void const *two)
{
- void const *a = (((module_instance_t const *)one)->dl_inst)->data;
- void const *b = (((module_instance_t const *)two)->dl_inst)->data;
+ void const *a = ((module_instance_t const *)one)->data;
+ void const *b = ((module_instance_t const *)two)->data;
return CMP(a, b);
}
* and will be appended to the parent's instance
* name.
*/
- mi = module_alloc(ml, module_by_data(ml, parent), DL_MODULE_TYPE_SUBMODULE, name, name);
+ mi = module_instance_alloc(ml, module_instance_by_data(ml, parent), DL_MODULE_TYPE_SUBMODULE, name, name);
if (unlikely(mi == NULL)) {
cf_log_err(submodule_cs, "Failed loading submodule");
return -1;
}
- if (unlikely(module_conf_parse(mi, submodule_cs) < 0)) {
+ if (unlikely(module_instance_conf_parse(mi, submodule_cs) < 0)) {
cf_log_err(submodule_cs, "Failed parsing submodule config");
talloc_free(mi);
return -1;
* - Module instance matching name.
* - NULL if no such module exists.
*/
-module_instance_t *module_by_name(module_list_t const *ml, module_instance_t const *parent, char const *asked_name)
+module_instance_t *module_instance_by_name(module_list_t const *ml, module_instance_t const *parent, char const *asked_name)
{
char const *inst_name;
void *inst;
inst = fr_rb_find(ml->name_tree,
&(module_instance_t){
- .dl_inst = &(dl_module_inst_t){ .parent = parent ? parent->dl_inst : NULL },
+ .parent = UNCONST(module_instance_t *, parent),
.name = inst_name
});
if (!inst) return NULL;
return talloc_get_type_abort(inst, module_instance_t);
}
-/** Find the module's parent (if any)
- *
- * @param[in] child to locate the parent for.
- * @return
- * - The module's parent.
- * - NULL on error.
- */
-module_instance_t *module_parent(module_instance_t const *child)
-{
- dl_module_inst_t const *parent;
-
- parent = dl_module_parent_instance(child->dl_inst);
- if (!parent) return NULL;
-
- return module_by_data(child->ml, parent->data);
-}
-
/** Find the module's shallowest parent
*
* @param[in] child to locate the root for.
* - The module's shallowest parent.
* - NULL on error.
*/
-module_instance_t *module_root(module_instance_t const *child)
+module_instance_t *module_instance_root(module_instance_t const *child)
{
- module_instance_t *next;
+ module_instance_t const *next;
for (;;) {
- next = module_parent(child);
+ next = child->parent;
if (!next) break;
child = next;
* - Module instance matching data.
* - NULL if no such module exists.
*/
-module_instance_t *module_by_data(module_list_t const *ml, void const *data)
+module_instance_t *module_instance_by_data(module_list_t const *ml, void const *data)
{
module_instance_t *mi;
mi = fr_rb_find(ml->data_tree,
&(module_instance_t){
- .dl_inst = &(dl_module_inst_t){ .data = UNCONST(void *, data) },
+ .data = UNCONST(void *, data)
});
if (!mi) return NULL;
return talloc_get_type_abort(mi, module_instance_t);
}
-
/** Retrieve module/thread specific instance for a module
*
* @param[in] mi to find thread specific data for.
* @param[in] ml Module list module belongs to.
* @param[in] data Private instance data of the module.
* Same as what would be provided by
- * #module_by_data.
+ * #module_instance_by_data.
* @return
* - Thread specific instance data on success.
* - NULL if module has no thread instance data.
*/
module_thread_instance_t *module_thread_by_data(module_list_t const *ml, void const *data)
{
- module_instance_t *mi = module_by_data(ml, data);
+ module_instance_t *mi = module_instance_by_data(ml, data);
module_thread_instance_t *ti;
if (!mi) return NULL;
module_list_in_sync = false; /* Help catch anything attempting to do lookups */
DEBUG4("Worker cleaning up %s thread instance data (%p/%p)",
- mi->module->name, ti, ti->data);
+ mi->exported->name, ti, ti->data);
- if (mi->module->thread_detach) {
- mi->module->thread_detach(&(module_thread_inst_ctx_t const ){
- .inst = ti->mi->dl_inst,
+ if (mi->exported->thread_detach) {
+ mi->exported->thread_detach(&(module_thread_inst_ctx_t const ){
+ .inst = ti->mi,
.thread = ti->data,
.el = ti->el
});
ti->el = el;
ti->mi = mi;
- if (mi->module->thread_inst_size) {
+ if (mi->exported->thread_inst_size) {
module_instance_t *rmi;
- MEM(ti->data = talloc_zero_array(ti, uint8_t, mi->module->thread_inst_size));
- rmi = module_root(mi);
+ MEM(ti->data = talloc_zero_array(ti, uint8_t, mi->exported->thread_inst_size));
+ rmi = module_instance_root(mi);
/*
* Fixup the type name, in case something calls
* talloc_get_type_abort() on it...
*/
- if (!mi->module->thread_inst_type) {
+ if (!mi->exported->thread_inst_type) {
talloc_set_name(ti->data, "%s_%s_thread_t",
fr_table_str_by_value(dl_module_type_prefix,
- rmi ? rmi->dl_inst->module->type :
- mi->dl_inst->module->type,
+ rmi ? rmi->module->type :
+ mi->module->type,
"<INVALID>"),
- mi->module->name);
+ mi->exported->name);
} else {
- talloc_set_name_const(ti->data, mi->module->thread_inst_type);
+ talloc_set_name_const(ti->data, mi->exported->thread_inst_type);
}
}
*/
fr_strerror_clear();
- DEBUG4("Alloced %s thread instance data (%p/%p)", ti->mi->module->name, ti, ti->data);
- if (mi->module->thread_instantiate &&
- mi->module->thread_instantiate(MODULE_THREAD_INST_CTX(mi->dl_inst, ti->data, el)) < 0) {
+ DEBUG4("Alloced %s thread instance data (%p/%p)", ti->mi->exported->name, ti, ti->data);
+ if (mi->exported->thread_instantiate &&
+ mi->exported->thread_instantiate(MODULE_THREAD_INST_CTX(mi, ti->data, el)) < 0) {
PERROR("Thread instantiation failed for module \"%s\"", mi->name);
/* Leave module_thread_inst_list intact, other modules may need to clean up */
modules_thread_detach(ml);
int module_instantiate(module_instance_t *instance)
{
module_instance_t *mi = talloc_get_type_abort(instance, module_instance_t);
- CONF_SECTION *cs = mi->dl_inst->conf;
+ CONF_SECTION *cs = mi->conf;
/*
* We only instantiate modules in the bootstrapped state
*/
if (mi->state != MODULE_INSTANCE_BOOTSTRAPPED) return 0;
- if (mi->dl_inst->module->type == DL_MODULE_TYPE_MODULE) {
+ if (mi->module->type == DL_MODULE_TYPE_MODULE) {
if (fr_command_register_hook(NULL, mi->name, mi, module_cmd_table) < 0) {
PERROR("Failed registering radmin commands for module %s", mi->name);
return -1;
* Now that ALL modules are instantiated, and ALL xlats
* are defined, go compile the config items marked as XLAT.
*/
- if (mi->module->config && (cf_section_parse_pass2(mi->dl_inst->data,
- mi->dl_inst->conf) < 0)) return -1;
+ if (mi->exported->config && (cf_section_parse_pass2(mi->data,
+ mi->conf) < 0)) return -1;
/*
* Call the instantiate method, if any.
*/
- if (mi->module->instantiate) {
+ if (mi->exported->instantiate) {
cf_log_debug(cs, "Instantiating %s_%s \"%s\"",
- dl_module_instance_root_prefix_str(mi->dl_inst),
- mi->dl_inst->module->common->name,
+ module_instance_root_prefix_str(mi),
+ mi->module->exported->name,
mi->name);
/*
* Call the module's instantiation routine.
*/
- if (mi->module->instantiate(MODULE_INST_CTX(mi->dl_inst)) < 0) {
- cf_log_err(mi->dl_inst->conf, "Instantiation failed for module \"%s\"", mi->name);
+ if (mi->exported->instantiate(MODULE_INST_CTX(mi)) < 0) {
+ cf_log_err(mi->conf, "Instantiation failed for module \"%s\"", mi->name);
return -1;
}
* in the trees if it needs to bootstrap
* submodules.
*/
- if (mi->module->bootstrap) {
- CONF_SECTION *cs = mi->dl_inst->conf;
+ if (mi->exported->bootstrap) {
+ CONF_SECTION *cs = mi->conf;
cf_log_debug(cs, "Bootstrapping %s_%s \"%s\"",
- dl_module_instance_root_prefix_str(mi->dl_inst),
- mi->dl_inst->module->common->name,
+ module_instance_root_prefix_str(mi),
+ mi->module->exported->name,
mi->name);
- if (mi->module->bootstrap(MODULE_INST_CTX(mi->dl_inst)) < 0) {
+ if (mi->exported->bootstrap(MODULE_INST_CTX(mi)) < 0) {
cf_log_err(cs, "Bootstrap failed for module \"%s\"", mi->name);
return -1;
}
*
* @param[in] ctx Where to allocate the module name.
* @param[out] out Where to write a pointer to the instance name.
- * @param[in] ml Module list in which to find the parent.
* @param[in] parent of the module.
* @param[in] inst_name module's instance name.
*/
-static fr_slen_t module_instance_name(TALLOC_CTX *ctx, char **out, module_list_t const *ml,
+static fr_slen_t module_instance_name(TALLOC_CTX *ctx, char **out,
module_instance_t const *parent, char const *inst_name)
{
fr_sbuff_t *agg;
+ module_instance_t const *mi;
FR_SBUFF_TALLOC_THREAD_LOCAL(&agg, 64, 256);
- while (parent) {
- FR_SBUFF_IN_STRCPY_RETURN(agg, parent->name);
+ for (mi = parent; mi; mi = mi->parent) {
+ FR_SBUFF_IN_STRCPY_RETURN(agg, mi->name);
FR_SBUFF_IN_CHAR_RETURN(agg, '.');
-
- if (!parent->dl_inst->parent) break;
-
- parent = module_by_data(ml, parent->dl_inst->parent->data);
}
FR_SBUFF_IN_STRCPY_RETURN(agg, inst_name);
MEM(*out = talloc_bstrndup(ctx, fr_sbuff_start(agg), fr_sbuff_used(agg)));
return fr_sbuff_used(agg);
-
}
/** Free module's instance data, and any xlats or paircmps
if (fr_rb_node_inline_in_tree(&mi->data_node) && !fr_cond_assert(fr_rb_delete(ml->data_tree, mi))) return 1;
/*
- * mi->module may be NULL if we failed loading the module
+ * mi->exported may be NULL if we failed loading the module
*/
- if (mi->module && ((mi->module->flags & MODULE_TYPE_THREAD_UNSAFE) != 0)) {
+ if (mi->exported && ((mi->exported->flags & MODULE_TYPE_THREAD_UNSAFE) != 0)) {
#ifndef NDEBUG
int ret;
/*
* Remove all xlat's registered to module instance.
*/
- if (mi->dl_inst && mi->dl_inst->data) {
+ if (mi && mi->data) {
xlat_func_unregister(mi->name);
- xlat_func_unregister_module(mi->dl_inst);
+ xlat_func_unregister_module(mi);
}
+ module_detach_parent(mi);
+
/*
* We need to explicitly free all children, so the module instance
* destructors get executed before we unload the bytecode for the
*/
talloc_free_children(mi);
- return 0;
-}
-
-/** Parse the configuration associated with a module
- *
- * @param[in] mi To parse the configuration for.
- * @param[in] mod_conf To parse.
- * @return
- * - 0 on success.
- * - -1 on failure.
- */
-int module_conf_parse(module_instance_t *mi, CONF_SECTION *mod_conf)
-{
- if (dl_module_conf_parse(mi->dl_inst, mod_conf) < 0) return -1;
+ dl_module_free(mi->module);
return 0;
}
* and private instance data.
* - NULL on error.
*/
-module_instance_t *module_alloc(module_list_t *ml,
- module_instance_t const *parent,
- dl_module_type_t type, char const *mod_name, char const *inst_name)
+module_instance_t *module_instance_alloc(module_list_t *ml,
+ module_instance_t const *parent,
+ dl_module_type_t type, char const *mod_name, char const *inst_name)
{
char *qual_inst_name = NULL;
module_instance_t *mi;
* Takes the inst_name and adds qualifiers
* if this is a submodule.
*/
- if (module_instance_name(NULL, &qual_inst_name, ml, parent, inst_name) < 0) {
+ if (module_instance_name(NULL, &qual_inst_name, parent, inst_name) < 0) {
ERROR("Module name too long");
return NULL;
}
/*
* See if the module already exists.
*/
- mi = module_by_name(ml, parent, qual_inst_name);
+ mi = module_instance_by_name(ml, parent, qual_inst_name);
if (mi) {
/*
* We may not have configuration data yet
* for the duplicate module.
*/
- if (mi->dl_inst->conf) {
+ if (mi->conf) {
ERROR("Duplicate %s_%s instance \"%s\", previous instance defined at %s[%d]",
- fr_table_str_by_value(dl_module_type_prefix, mi->dl_inst->module->type, "<INVALID>"),
- mi->dl_inst->module->common->name,
+ fr_table_str_by_value(dl_module_type_prefix, mi->module->type, "<INVALID>"),
+ mi->module->exported->name,
qual_inst_name,
- cf_filename(mi->dl_inst->conf),
- cf_lineno(mi->dl_inst->conf));
+ cf_filename(mi->conf),
+ cf_lineno(mi->conf));
} else {
ERROR("Duplicate %s_%s instance \"%s\"",
- fr_table_str_by_value(dl_module_type_prefix, mi->dl_inst->module->type, "<INVALID>"),
- mi->dl_inst->module->common->name,
+ fr_table_str_by_value(dl_module_type_prefix, mi->module->type, "<INVALID>"),
+ mi->module->exported->name,
qual_inst_name);
}
talloc_free(qual_inst_name);
}
MEM(mi = talloc_zero(parent ? (void const *)parent : (void const *)ml, module_instance_t));
- if (dl_module_instance(mi, &mi->dl_inst, parent ? parent->dl_inst : NULL,
- type, mod_name, qual_inst_name) < 0) {
+ mi->name = talloc_typed_strdup(mi, qual_inst_name);
+ talloc_free(qual_inst_name); /* Avoid stealing */
+
+ mi->ml = ml;
+ mi->parent = parent;
+
+ /*
+ * Increment the reference count on an already loaded module,
+ * or load the .so or .dylib, and run all the global callbacks.
+ */
+ mi->module = dl_module_alloc(parent ? parent->module : NULL, mod_name, type);
+ if (!mi->module) {
error:
- mi->name = qual_inst_name; /* Assigned purely for debug log output when mi is freed */
talloc_free(mi);
- talloc_free(qual_inst_name);
return NULL;
}
- fr_assert(mi->dl_inst);
- mi->module = (module_t const *)mi->dl_inst->module->common;
- if (!mi->module) {
+ /*
+ * We have no way of checking if this is correct... so we hope...
+ */
+ mi->exported = (module_t const *)mi->module->exported;
+ if (unlikely(mi->exported == NULL)) {
ERROR("Missing public structure for \"%s\"", qual_inst_name);
- talloc_free(mi);
- return NULL;
+ goto error;
}
+ /*
+ * Allocate the module instance data.
+ */
+ module_instance_data_alloc(mi);
+
/*
* If we're threaded, check if the module is thread-safe.
*
* Do this here so the destructor can trylock the mutex
* correctly even if bootstrap/instantiation fails.
*/
- if ((mi->module->flags & MODULE_TYPE_THREAD_UNSAFE) != 0) pthread_mutex_init(&mi->mutex, NULL);
- talloc_set_destructor(mi, _module_instance_free);
-
- mi->name = talloc_typed_strdup(mi, qual_inst_name);
- talloc_free(qual_inst_name); /* Avoid stealing */
+ if ((mi->exported->flags & MODULE_TYPE_THREAD_UNSAFE) != 0) pthread_mutex_init(&mi->mutex, NULL);
+ talloc_set_destructor(mi, _module_instance_free); /* Set late intentionally */
mi->number = ml->last_number++;
mi->ml = ml;
* Remember the module for later.
*/
if (!fr_cond_assert(fr_rb_insert(ml->name_tree, mi))) goto error;
-
- /*
- * Allow modules to get at their own
- * module_instance_t data, for
- * looking up thread specific data
- * and for bootstrapping submodules.
- */
- if (mi->dl_inst->data && !fr_cond_assert(fr_rb_insert(ml->data_tree, mi))) goto error;
+ if (!fr_cond_assert(fr_rb_insert(ml->data_tree, mi))) goto error;
/*
* ...and finally insert the module
* into the global heap so we can
* get common thread-local indexes.
*/
- if (fr_heap_insert(&module_global_inst_list, mi) < 0) goto error;
+ if (fr_heap_insert(&module_global_inst_list, mi) < 0) {
+ ERROR("Failed inserting into global module index");
+ goto error;
+ }
return mi;
}
*/
typedef int (*module_instantiate_t)(module_inst_ctx_t const *mctx);
+/** Wrapper structure around module_instance_t to allow us to pass more arguments into module_detach_ctx_t in future
+ */
+typedef struct {
+ module_instance_t const *inst; //!< Module instance to detach.
+} module_detach_ctx_t;
+
+/** Module detach callback
+ *
+ * Is called just before the server exits, and after re-instantiation on HUP,
+ * to free the old module instance.
+ *
+ * Detach should close all handles associated with the module instance, and
+ * free any memory allocated during instantiate.
+ *
+ * @param[in] inst to free.
+ * @return
+ * - 0 on success.
+ * - -1 if detach failed.
+ */
+typedef int (*module_detach_t)(module_detach_ctx_t const *inst);
+
/** Module thread creation callback
*
* Called whenever a new thread is created.
* within the module to different sections.
*/
struct module_s {
- DL_MODULE_COMMON; //!< Common fields for all loadable modules.
-
- module_instantiate_t bootstrap;
- module_instantiate_t instantiate;
- int flags; /* flags */
- module_thread_instantiate_t thread_instantiate;
- module_thread_detach_t thread_detach;
- char const *thread_inst_type;
- size_t thread_inst_size;
+ DL_MODULE_COMMON; //!< Common fields for all loadable modules.
+
+ conf_parser_t const *config; //!< How to convert a CONF_SECTION to a module instance.
+
+ size_t inst_size; //!< Size of the module's instance data.
+ char const *inst_type; //!< talloc type to assign to instance data.
+
+ module_instantiate_t bootstrap; //!< Callback to allow the module to register any global
+ ///< resources like xlat functions and attributes.
+ module_instantiate_t instantiate; //!< Callback to allow the module to register any
+ ///< per-instance resources like sockets and file handles.
+ module_detach_t detach; //!< Clean up module resources from both the bootstrap
+ ///< and instantiation pahses.
+
+ module_flags_t flags; //!< Flags that control how a module starts up and how
+ ///< a module is called.
+
+ module_thread_instantiate_t thread_instantiate; //!< Callback to populate a new module thread instance data.
+ ///< Called once per thread.
+ module_thread_detach_t thread_detach; //!< Callback to free thread-specific resources associated
+ ///!< with a module.
+
+ size_t thread_inst_size; //!< Size of the module's thread-specific instance data.
+ char const *thread_inst_type; //!< talloc type to assign to thread instance data.
};
/** What state the module instance is currently in
*
*/
typedef enum {
- MODULE_INSTANCE_INIT = 0,
- MODULE_INSTANCE_BOOTSTRAPPED,
- MODULE_INSTANCE_INSTANTIATED
+ MODULE_INSTANCE_INIT = 0, //!< Module instance has been allocated, but not
+ ///< yet bootstrapped.
+ MODULE_INSTANCE_BOOTSTRAPPED, //!< Module instance has been bootstrapped, but not
+ ///< yet instantiated.
+ MODULE_INSTANCE_INSTANTIATED //!< Module instance has been bootstrapped and
+ ///< instantiated.
} module_instance_state_t;
/** Per instance data
fr_heap_index_t inst_idx; //!< Entry in the bootstrap/instantiation heap.
//!< should be an identical value to the thread-specific
///< data for this module.
+ module_instance_state_t state; //!< What's been done with this module so far.
fr_rb_node_t name_node; //!< Entry in the name tree.
fr_rb_node_t data_node; //!< Entry in the data tree.
module_list_t *ml; //!< Module list this instance belongs to.
- uint32_t number; //!< Unique module number.
+ uint32_t number; //!< Unique module number. This is used to access the
+ ///< thread-specific module instance.
char const *name; //!< Instance name e.g. user_database.
- dl_module_inst_t *dl_inst; //!< Structure containing the module's instance data,
- //!< configuration, and dl handle. This can be used
- ///< to access the parsed configuration data for the
- ///< module.
+ dl_module_t *module; //!< dynamic loader handle. Contains the module's
+ ///< dlhandle, and the functions it exports.
+ ///< The dl_module is reference counted so that it
+ ///< can be freed automatically when the last instance
+ ///< is freed. This will also (usually) unload the
+ ///< .so or .dylib.
- module_t const *module; //!< Public module structure. Cached for convenience.
+ module_t const *exported; //!< Public module structure. Cached for convenience.
///< This exports module methods, i.e. the functions
///< which allow the module to perform actions.
+ ///< This is an identical address to dl_module->common,
+ ///< but with a different type, containing additional
+ ///< instance callbacks to make it easier to use.
- pthread_mutex_t mutex; //!< Used prevent multiple threads entering a thread
- ///< unsafe module simultaneously.
+ void *data; //!< Module's instance data.
+ CONF_SECTION *conf; //!< Module's instance configuration.
- module_instance_state_t state; //!< What's been done with this module so far.
+ module_instance_t const *parent; //!< Parent module's instance (if any).
+ pthread_mutex_t mutex; //!< Used prevent multiple threads entering a thread
+ ///< unsafe module simultaneously.
/** @name Return code overrides
* @{
*/
unlang_actions_t actions; //!< default actions and retries.
/** @} */
+
+ bool detached; //!< Whether the detach function has been called.
};
/** Per thread per instance data
*
* @{
*/
-module_instance_t *module_parent(module_instance_t const *child) CC_HINT(warn_unused_result);
+char const *module_instance_name_from_conf(CONF_SECTION *conf);
-module_instance_t *module_root(module_instance_t const *child); CC_HINT(warn_unused_result)
+int module_instance_conf_parse(module_instance_t *mi, CONF_SECTION *conf);
-module_instance_t *module_by_name(module_list_t const *ml, module_instance_t const *parent, char const *asked_name)
+char const *module_instance_root_prefix_str(module_instance_t const *mi) CC_HINT(nonnull) CC_HINT(warn_unused_result);
+
+module_instance_t *module_instance_root(module_instance_t const *child); CC_HINT(warn_unused_result)
+
+module_instance_t *module_instance_by_name(module_list_t const *ml, module_instance_t const *parent, char const *asked_name)
CC_HINT(nonnull(1,3)) CC_HINT(warn_unused_result);
-module_instance_t *module_by_data(module_list_t const *ml, void const *data) CC_HINT(warn_unused_result);
+module_instance_t *module_instance_by_data(module_list_t const *ml, void const *data) CC_HINT(warn_unused_result);
module_thread_instance_t *module_thread(module_instance_t *mi) CC_HINT(warn_unused_result);
int modules_bootstrap(module_list_t const *ml) CC_HINT(nonnull) CC_HINT(warn_unused_result);
-int module_conf_parse(module_instance_t *mi, CONF_SECTION *mod_cs) CC_HINT(nonnull) CC_HINT(warn_unused_result);
-
-module_instance_t *module_alloc(module_list_t *ml,
+module_instance_t *module_instance_alloc(module_list_t *ml,
module_instance_t const *parent,
dl_module_type_t type, char const *mod_name, char const *inst_name)
CC_HINT(nonnull(1)) CC_HINT(warn_unused_result);
*/
RCSIDH(module_ctx_h, "$Id$")
-#include <freeradius-devel/server/dl_module.h>
#include <freeradius-devel/util/event.h>
#ifdef __cplusplus
extern "C" {
#endif
+typedef struct module_instance_s module_instance_t;
/** Temporary structure to hold arguments for module calls
*
*/
typedef struct {
- dl_module_inst_t const *inst; //!< Dynamic loader API handle for the module.
+ module_instance_t const *inst; //!< Dynamic loader API handle for the module.
void *thread; //!< Thread specific instance data.
void *env_data; //!< Per call environment data.
void *rctx; //!< Resume ctx that a module previously set.
*
*/
typedef struct {
- dl_module_inst_t const *inst; //!< Dynamic loader API handle for the module.
+ module_instance_t const *inst; //!< Dynamic loader API handle for the module.
} module_inst_ctx_t;
/** Temporary structure to hold arguments for thread_instantiation calls
*
*/
typedef struct {
- dl_module_inst_t const *inst; //!< Dynamic loader API handle for the module.
+ module_instance_t const *inst; //!< Dynamic loader API handle for the module.
///< Must come first to allow cast between
///< module_inst_ctx.
void *thread; //!< Thread instance data.
///< and timers against.
} module_thread_inst_ctx_t;
+#ifdef __cplusplus
+}
+#endif
+
+#include <freeradius-devel/server/module.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
DIAG_OFF(unused-function)
/** Allocate a module calling ctx on the heap based on an instance ctx
*
* which don't set the required fields. Additional arguments should be added
* to this macro whenever the module_ctx_t fields are altered.
*
- * @param[in] _dl_inst of the module being called.
+ * @param[in] _mi of the module being called.
* @param[in] _thread instance of the module being called.
* @param[in] _env_data Call environment data.
* @param[in] _rctx Resume ctx (if any).
*/
-#define MODULE_CTX(_dl_inst, _thread, _env_data, _rctx) &(module_ctx_t){ .inst = _dl_inst, .thread = _thread, .env_data = _env_data, .rctx = _rctx }
+#define MODULE_CTX(_mi, _thread, _env_data, _rctx) &(module_ctx_t){ .inst = _mi, .thread = _thread, .env_data = _env_data, .rctx = _rctx }
/** Wrapper to create a module_ctx_t as a compound literal from a module_inst_ctx_t
*
* which don't set the required fields. Additional arguments should be added
* to this macro whenever the module_inst_ctx_t fields are altered.
*
- * @param[in] _dl_inst of the module being called..
+ * @param[in] _mi of the module being called..
*/
-#define MODULE_INST_CTX(_dl_inst) &(module_inst_ctx_t){ .inst = _dl_inst }
+#define MODULE_INST_CTX(_mi) &(module_inst_ctx_t){ .inst = _mi }
/** Wrapper to create a module_thread_inst_ctx_t as a compound literal
*
* which don't set the required fields. Additional arguments should be added
* to this macro whenever the module_thread_inst_ctx_t fields are altered.
*
- * @param[in] _dl_inst of the module being called.
+ * @param[in] _mi of the module being called.
* @param[in] _thread instance of the module being called.
* @param[in] _el Thread specific event list.
*/
-#define MODULE_THREAD_INST_CTX(_dl_inst, _thread, _el) &(module_thread_inst_ctx_t){ .inst = _dl_inst, .thread = _thread, .el = _el }
+#define MODULE_THREAD_INST_CTX(_mi, _thread, _el) &(module_thread_inst_ctx_t){ .inst = _mi, .thread = _thread, .el = _el }
/** Wrapper to create a module_inst_ctx_t as a comound listeral from a module_thread_ctx_t
*
- * Extract the dl_module_inst_t from a module_thread_inst_ctx_t.
+ * Extract the module_instance_t from a module_thread_inst_ctx_t.
*
* @param[in] _mctx to extract module_thread_inst_ctx_t from.
*/
* instantiation order issues.
*/
inst_name = cf_pair_value(cp);
- mi = module_by_name(rlm_modules, NULL, inst_name);
+ mi = module_instance_by_name(rlm_modules, NULL, inst_name);
if (!mi) {
cf_log_err(cp, "Unknown module instance \"%s\"", inst_name);
parent = tmp;
} while (true);
- if (unlikely(module_instantiate(module_by_name(rlm_modules, NULL, inst_name)) < 0)) return -1;
+ if (unlikely(module_instantiate(module_instance_by_name(rlm_modules, NULL, inst_name)) < 0)) return -1;
}
/*
/*
* Check the module instances are of the same type.
*/
- if (strcmp(cf_section_name1(mi->dl_inst->conf), cf_section_name1(module)) != 0) {
+ if (strcmp(cf_section_name1(mi->conf), cf_section_name1(module)) != 0) {
cf_log_err(cp, "Referenced module is a rlm_%s instance, must be a rlm_%s instance",
- cf_section_name1(mi->dl_inst->conf), cf_section_name1(module));
+ cf_section_name1(mi->conf), cf_section_name1(module));
return -1;
}
- *out = cf_section_find(mi->dl_inst->conf, name, NULL);
+ *out = cf_section_find(mi->conf, name, NULL);
return 1;
}
* Module names are allowed to contain '.'
* so we search for the bare module name first.
*/
- mi = module_by_name(rlm_modules, NULL, name);
+ mi = module_instance_by_name(rlm_modules, NULL, name);
if (mi) {
virtual_server_method_t const *allowed_list;
if (!method) return mi;
- mrlm = module_rlm_from_module(mi->module);
+ mrlm = module_rlm_from_module(mi->exported);
/*
* We're not searching for a named method, OR the
do {
*p = '\0';
- mi = module_by_name(rlm_modules, NULL, inst_name);
+ mi = module_instance_by_name(rlm_modules, NULL, inst_name);
if (mi) break;
/*
return NULL;
}
- mrlm = module_rlm_from_module(mi->module);
+ mrlm = module_rlm_from_module(mi->exported);
/*
* We have a module, but the caller doesn't care about
module_instance_t *module_rlm_by_name(module_instance_t const *parent, char const *asked_name)
{
- return module_by_name(rlm_modules, parent, asked_name);
+ return module_instance_by_name(rlm_modules, parent, asked_name);
}
/** Create a virtual module.
{
char const *name;
bool all_same;
- module_t const *last = NULL;
+ module_t const *last = NULL;
CONF_ITEM *sub_ci = NULL;
CONF_PAIR *cp;
module_instance_t *mi;
/*
* Ensure that the module doesn't exist.
*/
- mi = module_by_name(rlm_modules, NULL, name);
+ mi = module_instance_by_name(rlm_modules, NULL, name);
if (mi) {
ERROR("Duplicate module \"%s\" in file %s[%d] and file %s[%d]",
name,
cf_filename(cs),
cf_lineno(cs),
- cf_filename(mi->dl_inst->conf),
- cf_lineno(mi->dl_inst->conf));
+ cf_filename(mi->conf),
+ cf_lineno(mi->conf));
return -1;
}
if (all_same) {
if (!last) {
- last = mi->module;
- } else if (last != mi->module) {
+ last = mi->exported;
+ } else if (last != mi->exported) {
last = NULL;
all_same = false;
}
continue;
}
- mi = module_alloc(rlm_modules, NULL, DL_MODULE_TYPE_MODULE, name, dl_module_inst_name_from_conf(subcs));
+ mi = module_instance_alloc(rlm_modules, NULL, DL_MODULE_TYPE_MODULE, name, module_instance_name_from_conf(subcs));
if (unlikely(mi == NULL)) {
cf_log_perr(subcs, "Failed loading module");
return -1;
}
- if (module_conf_parse(mi, subcs) < 0) {
+ if (module_instance_conf_parse(mi, subcs) < 0) {
cf_log_perr(subcs, "Failed parsing module config");
- error:
talloc_free(mi);
return -1;
}
* Compile the default "actions" subsection, which includes retries.
*/
actions = cf_section_find(subcs, "actions", NULL);
- if (actions && unlang_compile_actions(&mi->actions, actions, (mi->module->flags & MODULE_TYPE_RETRY) != 0)) goto error;
+ if (actions && unlang_compile_actions(&mi->actions, actions, (mi->exported->flags & MODULE_TYPE_RETRY) != 0)) {
+ talloc_free(mi);
+ return -1;
+ }
}
/*
*
* The instance name is the virtual server name.
*/
- mi = module_alloc(process_modules, NULL, DL_MODULE_TYPE_PROCESS,
- module_name, dl_module_inst_name_from_conf(server_cs));
+ mi = module_instance_alloc(process_modules, NULL, DL_MODULE_TYPE_PROCESS,
+ module_name, module_instance_name_from_conf(server_cs));
talloc_free(module_name);
if (mi == NULL) {
+ error:
cf_log_perr(ci, "Failed loading process module");
return -1;
}
- process = (fr_process_module_t const *)mi->dl_inst->module->common;
+ if (unlikely(module_instance_conf_parse(mi, mi->conf) < 0)) goto error;
+
+ process = (fr_process_module_t const *)mi->module->exported;
if (!*(process->dict)) {
cf_log_err(ci, "Process module is invalid - missing namespace dictionary");
talloc_free(mi);
* fixups here.
*/
server->process_mi = mi;
- server->process_module = (fr_process_module_t const *)mi->dl_inst->module->common;
+ server->process_module = (fr_process_module_t const *)mi->module->exported;
*(module_instance_t const **)out = mi;
process_cs = cf_section_alloc(server_cs, server_cs, namespace, NULL);
}
- if (module_conf_parse(mi, process_cs) < 0) {
+ if (module_instance_conf_parse(mi, process_cs) < 0) {
cf_log_perr(ci, "Failed bootstrapping process module");
cf_data_remove(server_cs, module_instance_t, "process_module");
cf_data_remove(server_cs, fr_dict_t, "dict");
* Pull the list of sections we need to compile out of
* the process module's public struct.
*/
- add_compile_list(server->process_mi->dl_inst->conf, server->process_module->compile_list, namespace);
+ add_compile_list(server->process_mi->conf, server->process_module->compile_list, namespace);
return 0;
}
if (!inst_name) inst_name = mod_name;
MEM(qual_inst_name = talloc_asprintf(NULL, "%s.%s", cf_section_name2(server_cs), inst_name));
- mi = module_alloc(proto_modules, NULL, DL_MODULE_TYPE_PROTO, mod_name, qual_inst_name);
+ mi = module_instance_alloc(proto_modules, NULL, DL_MODULE_TYPE_PROTO, mod_name, qual_inst_name);
talloc_free(qual_inst_name);
if (!mi) {
+ error:
cf_log_err(listener_cs, "Failed loading listener");
return -1;
}
+ if (unlikely(module_instance_conf_parse(mi, listener_cs) < 0)) goto error;
if (DEBUG_ENABLED4) cf_log_debug(ci, "Loading %s listener into %p", inst_name, out);
- if (module_conf_parse(mi, listener_cs) < 0) {
- cf_log_perr(ci, "Failed parsing config for listener");
- talloc_free(mi);
- return -1;
- }
-
listener->proto_mi = mi;
- listener->proto_module = (fr_app_t const *)listener->proto_mi->dl_inst->module->common;
+ listener->proto_module = (fr_app_t const *)listener->proto_mi->module->exported;
cf_data_add(listener_cs, mi, "proto_module", false);
return 0;
* to create the fr_listen_t structure.
*/
if (listener->proto_module->open &&
- listener->proto_module->open(listener->proto_mi->dl_inst->data, sc,
- listener->proto_mi->dl_inst->conf) < 0) {
- cf_log_err(listener->proto_mi->dl_inst->conf,
+ listener->proto_module->open(listener->proto_mi->data, sc,
+ listener->proto_mi->conf) < 0) {
+ cf_log_err(listener->proto_mi->conf,
"Opening %s I/O interface failed",
listener->proto_module->common.name);
return -1;
fr_dict_t const *dict;
fr_virtual_server_t const *vs = virtual_servers[i];
fr_process_module_t const *process = (fr_process_module_t const *)
- vs->process_mi->dl_inst->module->common;
+ vs->process_mi->module->exported;
listeners = virtual_servers[i]->listeners;
listener_cnt = talloc_array_length(listeners);
fr_assert(listener->proto_module != NULL);
if (module_instantiate(listener->proto_mi) < 0) {
- cf_log_perr(listener->proto_mi->dl_inst->conf,
+ cf_log_perr(listener->proto_mi->conf,
"Failed instantiating listener");
return -1;
}
* Complete final instantiation of the process module
*/
if (module_instantiate(virtual_servers[i]->process_mi) < 0) {
- cf_log_perr(virtual_servers[i]->process_mi->dl_inst->conf,
+ cf_log_perr(virtual_servers[i]->process_mi->conf,
"Failed instantiating process module");
return -1;
}
fr_assert(parse_rules.attr.dict_def != NULL);
if (virtual_server_compile_sections(server_cs, process->compile_list, &parse_rules,
- vs->process_mi->dl_inst->data) < 0) {
+ vs->process_mi->data) < 0) {
return -1;
}
}
CONF_ITEM *ci, module_instance_t *inst, module_method_t method,
call_env_method_t const *method_env, char const *realname)
{
- module_rlm_t const *mrlm = module_rlm_from_module(inst->module);
+ module_rlm_t const *mrlm = module_rlm_from_module(inst->exported);
unlang_t *c;
unlang_module_t *single;
(unlang_ctx->rules->attr.dict_def != fr_dict_internal()) &&
!fr_dict_compatible(*(mrlm->dict), unlang_ctx->rules->attr.dict_def)) {
cf_log_err(ci, "The \"%s\" module can only be used with 'namespace = %s'. It cannot be used with 'namespace = %s'.",
- inst->module->name,
+ inst->module->exported->name,
fr_dict_root(*mrlm->dict)->name,
fr_dict_root(unlang_ctx->rules->attr.dict_def)->name);
return NULL;
* component.
*/
if (!method) {
- cf_log_err(ci, "Failed compiling %s - no method matching calling section found", inst->module->name);
+ cf_log_err(ci, "Failed compiling %s - no method matching calling section found", inst->name);
return NULL;
}
if (method_env) {
fr_assert_msg(method_env->inst_size, "Method environment for module %s, method %s %s declared, "
"but no inst_size set",
- inst->module->name, unlang_ctx->section_name1, unlang_ctx->section_name2);
+ inst->name, unlang_ctx->section_name1, unlang_ctx->section_name2);
if (!unlang_ctx->rules) {
- cf_log_err(ci, "Failed compiling %s - no rules", inst->module->name);
+ cf_log_err(ci, "Failed compiling %s - no rules", inst->name);
goto error;
}
single->call_env = call_env_alloc(single, single->self.name, method_env,
- unlang_ctx->rules, inst->dl_inst->conf,
+ unlang_ctx->rules, inst->conf,
unlang_ctx->section_name1, unlang_ctx->section_name2,
- single->instance->dl_inst->data);
+ single->instance->data);
if (!single->call_env) {
error:
talloc_free(c);
*/
if (cf_item_is_section(ci) &&
!unlang_compile_actions(&c->actions, cf_item_to_section(ci),
- (inst->module->flags & MODULE_TYPE_RETRY) != 0)) goto error;
+ (inst->exported->flags & MODULE_TYPE_RETRY) != 0)) goto error;
return c;
}
unlang_module_fd_event_t fd_read; //!< Function to call when FD is readable.
unlang_module_fd_event_t fd_write; //!< Function to call when FD is writable.
unlang_module_fd_event_t fd_error; //!< Function to call when FD has errored.
- dl_module_inst_t *dl_inst; //!< Module instance to pass to callbacks.
- ///< Use dl_inst->data to get instance data.
+ module_instance_t *mi; //!< Module instance to pass to callbacks.
+ ///< Use mi->data to get instance data.
void *thread; //!< Thread specific module instance.
void *env_data; //!< Per call environment data.
void const *rctx; //!< rctx data to pass to callbacks.
fr_assert(ev->fd == fd);
- ev->fd_read(MODULE_CTX(ev->dl_inst, ev->thread, ev->env_data, UNCONST(void *, ev->rctx)), ev->request, fd);
+ ev->fd_read(MODULE_CTX(ev->mi, ev->thread, ev->env_data, UNCONST(void *, ev->rctx)), ev->request, fd);
}
/** Frees an unlang event, removing it from the request's event loop
{
unlang_module_event_t *ev = talloc_get_type_abort(ctx, unlang_module_event_t);
- ev->timeout(MODULE_CTX(ev->dl_inst, ev->thread, ev->env_data, UNCONST(void *, ev->rctx)), ev->request, now);
+ ev->timeout(MODULE_CTX(ev->mi, ev->thread, ev->env_data, UNCONST(void *, ev->rctx)), ev->request, now);
talloc_free(ev);
}
.request = request,
.fd = -1,
.timeout = callback,
- .dl_inst = mc->instance->dl_inst,
+ .mi = mc->instance,
.thread = state->thread,
.env_data = state->env_data,
.rctx = rctx
unlang_module_event_t *ev = talloc_get_type_abort(ctx, unlang_module_event_t);
fr_assert(ev->fd == fd);
- ev->fd_write(MODULE_CTX(ev->dl_inst, ev->thread, ev->env_data, UNCONST(void *, ev->rctx)), ev->request, fd);
+ ev->fd_write(MODULE_CTX(ev->mi, ev->thread, ev->env_data, UNCONST(void *, ev->rctx)), ev->request, fd);
}
/** Call the callback registered for an I/O error event
fr_assert(ev->fd == fd);
- ev->fd_error(MODULE_CTX(ev->dl_inst, ev->thread, ev->env_data, UNCONST(void *, ev->rctx)), ev->request, fd);
+ ev->fd_error(MODULE_CTX(ev->mi, ev->thread, ev->env_data, UNCONST(void *, ev->rctx)), ev->request, fd);
}
ev->fd_read = read;
ev->fd_write = write;
ev->fd_error = error;
- ev->dl_inst = mc->instance->dl_inst;
+ ev->mi = mc->instance;
ev->thread = state->thread;
ev->env_data = state->env_data;
ev->rctx = rctx;
state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
return resume(p_result,
- MODULE_CTX(mc->instance->dl_inst, module_thread(mc->instance)->data,
+ MODULE_CTX(mc->instance, module_thread(mc->instance)->data,
state->env_data, rctx),
request);
}
*/
static inline CC_HINT(always_inline) void safe_lock(module_instance_t *mi)
{
- if ((mi->module->flags & MODULE_TYPE_THREAD_UNSAFE) != 0) pthread_mutex_lock(&mi->mutex);
+ if ((mi->exported->flags & MODULE_TYPE_THREAD_UNSAFE) != 0) pthread_mutex_lock(&mi->mutex);
}
/*
*/
static inline CC_HINT(always_inline) void safe_unlock(module_instance_t *mi)
{
- if ((mi->module->flags & MODULE_TYPE_THREAD_UNSAFE) != 0) pthread_mutex_unlock(&mi->mutex);
+ if ((mi->exported->flags & MODULE_TYPE_THREAD_UNSAFE) != 0) pthread_mutex_unlock(&mi->mutex);
}
/** Send a signal (usually stop) to a request
caller = request->module;
request->module = mc->instance->name;
safe_lock(mc->instance);
- if (!(action & state->sigmask)) state->signal(MODULE_CTX(mc->instance->dl_inst, state->thread->data, state->env_data, state->rctx), request, action);
+ if (!(action & state->sigmask)) state->signal(MODULE_CTX(mc->instance, state->thread->data, state->env_data, state->rctx), request, action);
safe_unlock(mc->instance);
request->module = caller;
* Lock is noop unless instance->mutex is set.
*/
safe_lock(mc->instance);
- ua = resume(&state->rcode, MODULE_CTX(mc->instance->dl_inst, state->thread->data,
+ ua = resume(&state->rcode, MODULE_CTX(mc->instance, state->thread->data,
state->env_data, state->rctx), request);
safe_unlock(mc->instance);
switch (ua) {
case UNLANG_ACTION_STOP_PROCESSING:
- RWARN("Module %s or worker signalled to stop processing request", mc->instance->module->name);
+ RWARN("Module %s or worker signalled to stop processing request", mc->instance->module->exported->name);
if (state->p_result) *state->p_result = state->rcode;
state->thread->active_callers--;
*p_result = state->rcode;
fr_assert(mc);
RDEBUG4("[%i] %s - %s (%s)", stack_depth_current(request), __FUNCTION__,
- mc->instance->name, mc->instance->module->name);
+ mc->instance->module->exported->name, mc->instance->name);
state->p_result = NULL;
request->module = mc->instance->name;
safe_lock(mc->instance); /* Noop unless instance->mutex set */
ua = mc->method(&state->rcode,
- MODULE_CTX(mc->instance->dl_inst, state->thread->data, state->env_data, NULL),
+ MODULE_CTX(mc->instance, state->thread->data, state->env_data, NULL),
request);
safe_unlock(mc->instance);
* must have been blocked.
*/
case UNLANG_ACTION_STOP_PROCESSING:
- RWARN("Module %s became unblocked", mc->instance->module->name);
+ RWARN("Module %s became unblocked", mc->instance->name);
if (state->p_result) *state->p_result = state->rcode;
*p_result = state->rcode;
request->module = state->previous_module;
*/
RCSIDH(xlat_ctx_h, "$Id$")
-#include <freeradius-devel/server/module_ctx.h>
+
#ifdef __cplusplus
extern "C" {
typedef struct xlat_exp_s xlat_exp_t;
typedef struct xlat_exp_head_s xlat_exp_head_t;
+/* Break dependency loop with module_ctx.h */
+typedef struct xlat_ctx_s xlat_ctx_t;
+typedef struct xlat_inst_ctx_s xlat_inst_ctx_t;
+typedef struct xlat_thread_inst_ctx_s xlat_thread_inst_ctx_t;
+
+#include <freeradius-devel/server/module_ctx.h>
+
/** An xlat calling ctx
*
* This provides optional arguments to xlat functions.
*/
-typedef struct {
+struct xlat_ctx_s {
void const *inst; //!< xlat instance data.
void *thread; //!< xlat threadinstance data.
module_ctx_t const *mctx; //!< Synthesised module calling ctx.
void *env_data; //!< Expanded call env data.
void *rctx; //!< Resume context.
-} xlat_ctx_t;
+};
/** An xlat instantiation ctx
*
* This provides optional arguments to xlat functions.
*/
-typedef struct {
+struct xlat_inst_ctx_s {
void *inst; //!< xlat instance data to populate.
xlat_exp_t *ex; //!< Tokenized expression to use in expansion.
module_inst_ctx_t const *mctx; //!< Synthesised module calling ctx.
void *uctx; //!< Passed to the registration function.
-} xlat_inst_ctx_t;
+};
/** An xlat thread instantiation ctx
*
* This provides optional arguments to xlat functions.
*/
-typedef struct {
+struct xlat_thread_inst_ctx_s {
void const *inst; //!< xlat instance data.
void *thread; //!< xlat thread instance data to populate.
xlat_exp_t const *ex; //!< Tokenized expression to use in expansion.
module_ctx_t const *mctx; //!< Synthesised module calling ctx.
fr_event_list_t *el; //!< To register any I/O handlers or timers against.
void *uctx; //!< Passed to the registration function.
-} xlat_thread_inst_ctx_t;
+};
/** Wrapper to create a xlat_ctx_t as a compound literal
*
talloc_free(c); /* Should also remove from tree */
}
-void xlat_func_unregister_module(dl_module_inst_t const *inst)
+void xlat_func_unregister_module(module_instance_t const *inst)
{
xlat_t *c;
fr_rb_iter_inorder_t iter;
void *uctx);
void xlat_func_unregister(char const *name);
-void xlat_func_unregister_module(dl_module_inst_t const *inst);
+void xlat_func_unregister_module(module_instance_t const *inst);
/** @hidecallgraph */
int xlat_func_init(void);
li->default_message_size = FR_ARP_PACKET_SIZE;
li->num_messages = inst->num_messages;
- li->app_io = inst->app_io;
- li->app_io_instance = inst->app_io_instance;
+ li->app_io = (fr_app_io_t const *)inst->io_submodule->module->exported;
+ li->app_io_instance = inst->io_submodule->data;
if (li->app_io->common.thread_inst_size) {
li->thread_instance = talloc_zero_array(NULL, uint8_t, li->app_io->common.thread_inst_size);
- talloc_set_name(li->thread_instance, "proto_%s_thread_t", inst->app_io->common.name);
+ talloc_set_name(li->thread_instance, "proto_%s_thread_t", li->app_io->common.name);
}
/*
* Open the raw socket.
*/
- if (inst->app_io->open(li) < 0) {
+ if (li->app_io->open(li) < 0) {
talloc_free(li);
return -1;
}
fr_assert(li->fd >= 0);
- li->name = inst->app_io->get_name(li);
+ li->name = li->app_io->get_name(li);
/*
* Watch the directory for changes.
static int mod_instantiate(module_inst_ctx_t const *mctx)
{
proto_arp_t *inst = talloc_get_type_abort(mctx->inst->data, proto_arp_t);
- CONF_SECTION *conf = mctx->inst->conf;
- /*
- * Instantiate the I/O module. But DON'T instantiate the
- * work submodule. We leave that until later.
- */
- if (inst->app_io->common.instantiate &&
- (inst->app_io->common.instantiate(MODULE_INST_CTX(inst->io_submodule->dl_inst)) < 0)) {
- cf_log_err(conf, "Instantiation failed for \"%s\"", inst->app_io->common.name);
- return -1;
- }
if (!inst->num_messages) inst->num_messages = 256;
{
proto_arp_t *inst = talloc_get_type_abort(mctx->inst->data, proto_arp_t);
CONF_SECTION *conf = mctx->inst->conf;
- dl_module_inst_t *parent_inst;
+ module_instance_t *parent_inst;
/*
* Ensure that the server CONF_SECTION is always set.
inst->server_cs = cf_item_to_section(cf_parent(conf));
inst->cs = conf;
- parent_inst = cf_data_value(cf_data_find(inst->cs, dl_module_inst_t, "proto_arp"));
+ parent_inst = cf_data_value(cf_data_find(inst->cs, module_instance_t, "proto_arp"));
fr_assert(parent_inst);
- if (dl_module_instance(inst->cs, &inst->io_submodule->dl_inst,
- parent_inst,
- DL_MODULE_TYPE_SUBMODULE, "ethernet", dl_module_inst_name_from_conf(inst->cs)) < 0) {
- cf_log_perr(inst->cs, "Failed to load proto_arp_ethernet");
- return -1;
- }
-
- if (dl_module_conf_parse(inst->io_submodule->dl_inst, inst->cs) < 0) {
- TALLOC_FREE(inst->io_submodule);
- return -1;
- }
-
- /*
- * Bootstrap the I/O module
- */
- inst->app_io = (fr_app_io_t const *) inst->io_submodule->dl_inst->module->common;
- inst->app_io_instance = inst->io_submodule->dl_inst->data;
- inst->app_io_conf = conf;
-
- if (inst->app_io->common.bootstrap && (inst->app_io->common.bootstrap(MODULE_INST_CTX(inst->io_submodule->dl_inst)) < 0)) {
- cf_log_err(inst->app_io_conf, "Bootstrap failed for \"%s\"", inst->app_io->common.name);
- return -1;
- }
-
return 0;
}
///< callback. Broken out into the
///< app_io_* fields below for convenience.
- CONF_SECTION *app_io_conf; //!< for the APP IO
- fr_app_io_t const *app_io; //!< Easy access to the app_io handle.
- void *app_io_instance; //!< Easy access to the app_io instance.
-
- dl_module_inst_t *app_process; //!< app_process pointer
+ module_instance_t *app_process; //!< app_process pointer
void *process_instance; //!< app_process instance
fr_dict_t *dict; //!< root dictionary
/*
* Instantiate the master io submodule
*/
- return fr_master_app_io.common.instantiate(MODULE_INST_CTX(inst->io.dl_inst));
+ return fr_master_app_io.common.instantiate(MODULE_INST_CTX(inst->io.mi));
}
/*
* We will need this for dynamic clients and connected sockets.
*/
- inst->io.dl_inst = dl_module_instance_by_data(inst);
- fr_assert(inst != NULL);
-
+ inst->io.mi = mctx->inst;
server = inst->io.server_cs;
inst->peers = cf_data_value(cf_data_find(server, fr_rb_tree_t, "peers"));
/*
* Bootstrap the master IO handler.
*/
- return fr_master_app_io.common.bootstrap(MODULE_INST_CTX(inst->io.dl_inst));
+ return fr_master_app_io.common.bootstrap(MODULE_INST_CTX(inst->io.mi));
}
static int mod_load(void)
/*
* Instantiate the master io submodule
*/
- return fr_master_app_io.common.instantiate(MODULE_INST_CTX(inst->io.dl_inst));
+ return fr_master_app_io.common.instantiate(MODULE_INST_CTX(inst->io.mi));
}
/*
* We will need this for dynamic clients and connected sockets.
*/
- inst->io.dl_inst = dl_module_instance_by_data(inst);
- fr_assert(inst != NULL);
+ inst->io.mi = mctx->inst;
/*
* Bootstrap the master IO handler.
*/
- return fr_master_app_io.common.bootstrap(MODULE_INST_CTX(inst->io.dl_inst));
+ return fr_master_app_io.common.bootstrap(MODULE_INST_CTX(inst->io.mi));
}
fr_app_t proto_control = {
{ NULL }
};
-/** Wrapper around dl_instance which translates the packet-type into a submodule name
+/** Translates the packet-type into a submodule name
*
* @param[in] ctx to allocate data in (instance of proto_cron).
- * @param[out] out Where to write a dl_module_inst_t containing the module handle and instance.
+ * @param[out] out Where to write a module_instance_t containing the module handle and instance.
* @param[in] parent Base structure address.
* @param[in] ci #CONF_PAIR specifying the name of the type module.
* @param[in] rule unused.
};
static size_t time_names_len = NUM_ELEMENTS(time_names);
-/** Wrapper around dl_instance which checks the syntax of a cron job
+/** Checks the syntax of a cron job
*
* @param[in] ctx to allocate data in (instance of proto_cron).
- * @param[out] out Where to write a dl_module_inst_t containing the module handle and instance.
+ * @param[out] out Where to write a module_instance_t containing the module handle and instance.
* @param[in] parent Base structure address.
* @param[in] ci #CONF_PAIR specifying the name of the type module.
* @param[in] rule unused.
CONF_PARSER_TERMINATOR
};
-/** Wrapper around dl_instance which translates the packet-type into a submodule name
+/** Translates the packet-type into a submodule name
*
* @param[in] ctx to allocate data in (instance of proto_cron).
- * @param[out] out Where to write a dl_module_inst_t containing the module handle and instance.
+ * @param[out] out Where to write a module_instance_t containing the module handle and instance.
* @param[in] parent Base structure address.
* @param[in] ci #CONF_PAIR specifying the name of the type module.
* @param[in] rule unused.
/*
* Instantiate the master io submodule
*/
- return fr_master_app_io.common.instantiate(MODULE_INST_CTX(inst->io.dl_inst));
+ return fr_master_app_io.common.instantiate(MODULE_INST_CTX(inst->io.mi));
}
/** Bootstrap the application
/*
* We will need this for dynamic clients and connected sockets.
*/
- inst->io.dl_inst = dl_module_instance_by_data(inst);
- fr_assert(inst != NULL);
+ inst->io.mi = mctx->inst;
/*
* Bootstrap the master IO handler.
*/
- return fr_master_app_io.common.bootstrap(MODULE_INST_CTX(inst->io.dl_inst));
+ return fr_master_app_io.common.bootstrap(MODULE_INST_CTX(inst->io.mi));
}
};
static size_t time_names_len = NUM_ELEMENTS(time_names);
-/** Wrapper around dl_instance which checks the syntax of a cron job
+/** Checks the syntax of a cron job
*
* @param[in] ctx to allocate data in (instance of proto_cron).
- * @param[out] out Where to write a dl_module_inst_t containing the module handle and instance.
+ * @param[out] out Where to write a module_instance_t containing the module handle and instance.
* @param[in] parent Base structure address.
* @param[in] ci #CONF_PAIR specifying the name of the type module.
* @param[in] rule unused.
static int mod_bootstrap(module_inst_ctx_t const *mctx)
{
proto_cron_crontab_t *inst = talloc_get_type_abort(mctx->inst->data, proto_cron_crontab_t);
- CONF_SECTION *conf = mctx->inst->data;
- dl_module_inst_t const *dl_inst;
-
- /*
- * Find the dl_module_inst_t holding our instance data
- * so we can find out what the parent of our instance
- * was.
- */
- dl_inst = dl_module_instance_by_data(inst);
- fr_assert(dl_inst);
-
- inst->parent = talloc_get_type_abort(dl_inst->parent->data, proto_cron_t);
- inst->cs = conf;
+ inst->parent = talloc_get_type_abort(mctx->inst->parent->data, proto_cron_t);
+ inst->cs = mctx->inst->conf;
return 0;
}
#include <freeradius-devel/util/pair_legacy.h>
#include "proto_detail.h"
+#include "lib/server/dl_module.h"
+#include "lib/server/module.h"
extern fr_app_t proto_detail;
static int type_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, conf_parser_t const *rule);
{ NULL }
};
-/** Wrapper around dl_instance which translates the packet-type into a submodule name
+/** Translates the packet-type into a submodule name
*
* @param[in] ctx to allocate data in (instance of proto_detail).
- * @param[out] out Where to write a dl_module_inst_t containing the module handle and instance.
+ * @param[out] out Where to write a module_instance_t containing the module handle and instance.
* @param[in] parent Base structure address.
* @param[in] ci #CONF_PAIR specifying the name of the type module.
* @param[in] rule unused.
* Testing: allow it to read a "detail.work" file
* directly.
*/
- if (strcmp(inst->io_submodule->dl_inst->module->dl->name, "proto_detail_work") == 0) {
+ if (strcmp(inst->io_submodule->module->dl->name, "proto_detail_work") == 0) {
if (!fr_schedule_listen_add(sc, li)) {
talloc_free(li);
return -1;
* work submodule. We leave that until later.
*/
if (inst->app_io->common.instantiate &&
- (inst->app_io->common.instantiate(MODULE_INST_CTX(inst->io_submodule->dl_inst)) < 0)) {
+ (inst->app_io->common.instantiate(MODULE_INST_CTX(inst->io_submodule)) < 0)) {
cf_log_err(conf, "Instantiation failed for \"%s\"", inst->app_io->common.name);
return -1;
}
/*
* If the IO is "file" and not the worker, instantiate the worker now.
*/
- if (strcmp(inst->io_submodule->dl_inst->module->dl->name, "proto_detail_work") != 0) {
+ if (strcmp(inst->io_submodule->module->dl->name, "proto_detail_work") != 0) {
if (inst->work_io->common.instantiate &&
(inst->work_io->common.instantiate(MODULE_INST_CTX(inst->work_submodule)) < 0)) {
cf_log_err(inst->work_io_conf, "Instantiation failed for \"%s\"", inst->work_io->common.name);
/*
* Bootstrap the I/O module
*/
- inst->app_io = (fr_app_io_t const *) inst->io_submodule->dl_inst->module->common;
- inst->app_io_instance = inst->io_submodule->dl_inst->data;
- inst->app_io_conf = inst->io_submodule->dl_inst->conf;
+ inst->app_io = (fr_app_io_t const *) inst->io_submodule->module->exported;
+ inst->app_io_instance = inst->io_submodule->data;
+ inst->app_io_conf = inst->io_submodule->conf;
- if (inst->app_io->common.bootstrap && (inst->app_io->common.bootstrap(MODULE_INST_CTX(inst->io_submodule->dl_inst)) < 0)) {
+ if (inst->app_io->common.bootstrap && (inst->app_io->common.bootstrap(MODULE_INST_CTX(inst->io_submodule)) < 0)) {
cf_log_err(inst->app_io_conf, "Bootstrap failed for \"%s\"", inst->app_io->common.name);
return -1;
}
/*
* If we're not loading the work submodule directly, then try to load it here.
*/
- if (strcmp(inst->io_submodule->dl_inst->module->dl->name, "proto_detail_work") != 0) {
+ if (strcmp(inst->io_submodule->module->dl->name, "proto_detail_work") != 0) {
CONF_SECTION *transport_cs;
- dl_module_inst_t *parent_inst;
+ module_instance_t *parent_inst;
inst->work_submodule = NULL;
transport_cs = cf_section_find(inst->cs, "work", NULL);
- parent_inst = cf_data_value(cf_data_find(inst->cs, dl_module_inst_t, "proto_detail"));
+ parent_inst = cf_data_value(cf_data_find(inst->cs, module_instance_t, "proto_detail"));
fr_assert(parent_inst);
if (!transport_cs) {
}
}
- if (dl_module_instance(parent_inst, &inst->work_submodule,
- parent_inst,
- DL_MODULE_TYPE_SUBMODULE, "work", dl_module_inst_name_from_conf(transport_cs)) < 0) {
+ /*
+ * This *should* get bootstrapped at some point after this module
+ * as it's inserted into the three the caller is iterating over.
+ *
+ * We might want to revisit this, and use a linked list of modules
+ * to iterate over instead of a tree, so we can add this to the end
+ * of that list.
+ */
+ inst->work_submodule = module_instance_alloc(parent_inst->ml, parent_inst, DL_MODULE_TYPE_SUBMODULE,
+ "work", module_instance_name_from_conf(transport_cs));
+ if (inst->work_submodule == NULL) {
+ error:
cf_log_perr(inst->cs, "Failed to load proto_detail_work");
- return -1;
- }
-
- if (dl_module_conf_parse(inst->work_submodule, transport_cs) < 0) {
TALLOC_FREE(inst->work_submodule);
return -1;
}
- /*
- * Boot strap the work module.
- */
- inst->work_io = (fr_app_io_t const *) inst->work_submodule->module->common;
+ if (module_instance_conf_parse(inst->work_submodule, transport_cs) < 0) goto error;
+
+ inst->work_io = (fr_app_io_t const *) inst->work_submodule->module->exported;
inst->work_io_instance = inst->work_submodule->data;
inst->work_io_conf = inst->work_submodule->conf;
-
- if (inst->work_io->common.bootstrap &&
- (inst->work_io->common.bootstrap(MODULE_INST_CTX(inst->work_submodule)) < 0)) {
- cf_log_err(inst->work_io_conf, "Bootstrap failed for \"%s\"", inst->work_io->common.name);
- TALLOC_FREE(inst->work_submodule);
- return -1;
- }
}
return 0;
CONF_SECTION *app_io_conf; //!< Easy access to the app_io's config section.
// proto_detail_app_io_t *app_io_private; //!< Internal interface for proto_radius.
- dl_module_inst_t *work_submodule; //!< the worker
+ module_instance_t *work_submodule; //!< the worker
fr_app_io_t const *work_io; //!< Easy access to the app_io handle.
void *work_io_instance; //!< Easy access to the app_io instance.
{
proto_detail_file_t *inst = talloc_get_type_abort(mctx->inst->data, proto_detail_file_t);
CONF_SECTION *conf = mctx->inst->conf;
- dl_module_inst_t const *dl_inst;
+ module_instance_t const *mi;
char *p;
#ifdef __linux__
#endif
/*
- * Find the dl_module_inst_t holding our instance data
+ * Find the module_instance_t holding our instance data
* so we can find out what the parent of our instance
* was.
*/
- dl_inst = dl_module_instance_by_data(mctx->inst->data);
- fr_assert(dl_inst);
+ mi = mctx->inst;
#ifndef __linux__
/*
#endif
FR_INTEGER_BOUND_CHECK("poll_interval", inst->poll_interval, <=, 3600);
- inst->parent = talloc_get_type_abort(dl_inst->parent->data, proto_detail_t);
+ inst->parent = talloc_get_type_abort(mi->parent->data, proto_detail_t);
inst->cs = conf;
inst->directory = p = talloc_strdup(inst, inst->filename);
{
proto_detail_work_t *inst = talloc_get_type_abort(mctx->inst->data, proto_detail_work_t);
CONF_SECTION *cs = mctx->inst->conf;
- dl_module_inst_t const *dl_inst;
+ module_instance_t const *mi = mctx->inst;
- /*
- * Find the dl_module_inst_t holding our instance data
- * so we can find out what the parent of our instance
- * was.
- */
- dl_inst = dl_module_instance_by_data(mctx->inst->data);
- fr_assert(dl_inst);
-
- inst->parent = talloc_get_type_abort(dl_inst->parent->data, proto_detail_t);
+ inst->parent = talloc_get_type_abort(mi->parent->data, proto_detail_t);
inst->cs = cs;
if (inst->track_progress) {
{ NULL }
};
-/** Wrapper around dl_instance which translates the packet-type into a submodule name
+/** Translates the packet-type into a submodule name
*
* @param[in] ctx to allocate data in (instance of proto_dhcpv4).
- * @param[out] out Where to write a dl_module_inst_t containing the module handle and instance.
+ * @param[out] out Where to write a module_instance_t containing the module handle and instance.
* @param[in] parent Base structure address.
* @param[in] ci #CONF_PAIR specifying the name of the type module.
* @param[in] rule unused.
/*
* Instantiate the master io submodule
*/
- return fr_master_app_io.common.instantiate(MODULE_INST_CTX(inst->io.dl_inst));
+ return fr_master_app_io.common.instantiate(MODULE_INST_CTX(inst->io.mi));
}
/*
* We will need this for dynamic clients and connected sockets.
*/
- inst->io.dl_inst = dl_module_instance_by_data(inst);
- fr_assert(inst != NULL);
+ inst->io.mi = mctx->inst;
/*
* Bootstrap the master IO handler.
*/
- return fr_master_app_io.common.bootstrap(MODULE_INST_CTX(inst->io.dl_inst));
+ return fr_master_app_io.common.bootstrap(MODULE_INST_CTX(inst->io.mi));
}
static int mod_load(void)
{ NULL }
};
-/** Wrapper around dl_instance which translates the packet-type into a submodule name
+/** Translates the packet-type into a submodule name
*
* @param[in] ctx to allocate data in (instance of proto_dhcpv6).
- * @param[out] out Where to write a dl_module_inst_t containing the module handle and instance.
+ * @param[out] out Where to write a module_instance_t containing the module handle and instance.
* @param[in] parent Base structure address.
* @param[in] ci #CONF_PAIR specifying the name of the type module.
* @param[in] rule unused.
/*
* Instantiate the master io submodule
*/
- return fr_master_app_io.common.instantiate(MODULE_INST_CTX(inst->io.dl_inst));
+ return fr_master_app_io.common.instantiate(MODULE_INST_CTX(inst->io.mi));
}
/** Bootstrap the application
/*
* We will need this for dynamic clients and connected sockets.
*/
- inst->io.dl_inst = dl_module_instance_by_data(inst);
- fr_assert(inst != NULL);
+ inst->io.mi = mctx->inst;
/*
* Bootstrap the master IO handler.
*/
- return fr_master_app_io.common.bootstrap(MODULE_INST_CTX(inst->io.dl_inst));
+ return fr_master_app_io.common.bootstrap(MODULE_INST_CTX(inst->io.mi));
}
static int mod_load(void)
{ NULL }
};
-/** Wrapper around dl_instance which translates the packet-type into a submodule name
+/** Translates the packet-type into a submodule name
*
* @param[in] ctx to allocate data in (instance of proto_dns).
- * @param[out] out Where to write a dl_module_inst_t containing the module handle and instance.
+ * @param[out] out Where to write a module_instance_t containing the module handle and instance.
* @param[in] parent Base structure address.
* @param[in] ci #CONF_PAIR specifying the name of the type module.
* @param[in] rule unused.
/*
* Instantiate the master io submodule
*/
- return fr_master_app_io.common.instantiate(MODULE_INST_CTX(inst->io.dl_inst));
+ return fr_master_app_io.common.instantiate(MODULE_INST_CTX(inst->io.mi));
}
/** Bootstrap the application
/*
* We will need this for dynamic clients and connected sockets.
*/
- inst->io.dl_inst = dl_module_instance_by_data(inst);
- fr_assert(inst != NULL);
+ inst->io.mi = mctx->inst;
/*
* Bootstrap the master IO handler.
*/
- return fr_master_app_io.common.bootstrap(MODULE_INST_CTX(inst->io.dl_inst));
+ return fr_master_app_io.common.bootstrap(MODULE_INST_CTX(inst->io.mi));
}
static int mod_load(void)
* Instantiate the I/O module.
*/
if (inst->app_io->common.instantiate &&
- (inst->app_io->common.instantiate(MODULE_INST_CTX(inst->io_submodule->dl_inst)) < 0)) {
+ (inst->app_io->common.instantiate(MODULE_INST_CTX(inst->io_submodule)) < 0)) {
cf_log_err(conf, "Instantiation failed for \"%s\"", inst->app_io->common.name);
return -1;
}
/*
* Bootstrap the I/O module
*/
- inst->app_io = (fr_app_io_t const *) inst->io_submodule->dl_inst->module->common;
- inst->app_io_instance = inst->io_submodule->dl_inst->data;
- inst->app_io_conf = inst->io_submodule->dl_inst->conf;
+ inst->app_io = (fr_app_io_t const *) inst->io_submodule->module->exported;
+ inst->app_io_instance = inst->io_submodule->data;
+ inst->app_io_conf = inst->io_submodule->conf;
if (inst->app_io->common.bootstrap &&
- (inst->app_io->common.bootstrap(MODULE_INST_CTX(inst->io_submodule->dl_inst)) < 0)) {
+ (inst->app_io->common.bootstrap(MODULE_INST_CTX(inst->io_submodule)) < 0)) {
cf_log_err(inst->app_io_conf, "Bootstrap failed for \"%s\"", inst->app_io->common.name);
return -1;
}
{
proto_ldap_sync_ldap_t *inst = talloc_get_type_abort(mctx->inst->data, proto_ldap_sync_ldap_t);
CONF_SECTION *conf = mctx->inst->conf;
- dl_module_inst_t const *dl_inst;
+ module_instance_t const *mi = mctx->inst;
- dl_inst = dl_module_instance_by_data(inst);
- fr_assert(dl_inst);
-
- inst->parent = talloc_get_type_abort(dl_inst->parent->data, proto_ldap_sync_t);
+ inst->parent = talloc_get_type_abort(mi->parent->data, proto_ldap_sync_t);
inst->cs = conf;
if (inst->recv_buff_is_set) {
CONF_PARSER_TERMINATOR
};
-/** Wrapper around dl_instance which translates the packet-type into a submodule name
+/** Translates the packet-type into a submodule name
*
* @param[in] ctx to allocate data in (instance of proto_load).
- * @param[out] out Where to write a dl_module_inst_t containing the module handle and instance.
+ * @param[out] out Where to write a module_instance_t containing the module handle and instance.
* @param[in] parent Base structure address.
* @param[in] ci #CONF_PAIR specifying the name of the type module.
* @param[in] rule unused.
/*
* Instantiate the master io submodule
*/
- return fr_master_app_io.common.instantiate(MODULE_INST_CTX(inst->io.dl_inst));
+ return fr_master_app_io.common.instantiate(MODULE_INST_CTX(inst->io.mi));
}
/** Bootstrap the application
/*
* We will need this for dynamic clients and connected sockets.
*/
- inst->io.dl_inst = dl_module_instance_by_data(inst);
- fr_assert(inst != NULL);
+ inst->io.mi = mctx->inst;
/*
* Bootstrap the master IO handler.
*/
- return fr_master_app_io.common.bootstrap(MODULE_INST_CTX(inst->io.dl_inst));
+ return fr_master_app_io.common.bootstrap(MODULE_INST_CTX(inst->io.mi));
}
{
proto_load_step_t *inst = talloc_get_type_abort(mctx->inst->data, proto_load_step_t);
CONF_SECTION *conf = mctx->inst->conf;
- dl_module_inst_t const *dl_inst;
+ module_instance_t const *mi = mctx->inst;
- /*
- * Find the dl_module_inst_t holding our instance data
- * so we can find out what the parent of our instance
- * was.
- */
- dl_inst = dl_module_instance_by_data(inst);
- fr_assert(dl_inst);
-
- inst->parent = talloc_get_type_abort(dl_inst->parent->data, proto_load_t);
+ inst->parent = talloc_get_type_abort(mi->parent->data, proto_load_t);
inst->cs = conf;
FR_INTEGER_BOUND_CHECK("start_pps", inst->load.start_pps, >=, 10);
{ NULL }
};
-/** Wrapper around dl_instance which translates the packet-type into a submodule name
+/** Translates the packet-type into a submodule name
*
* If we found a Packet-Type = Access-Request CONF_PAIR for example, here's we'd load
* the proto_radius_auth module.
*
* @param[in] ctx to allocate data in (instance of proto_radius).
- * @param[out] out Where to write a dl_module_inst_t containing the module handle and instance.
+ * @param[out] out Where to write a module_instance_t containing the module handle and instance.
* @param[in] parent Base structure address.
* @param[in] ci #CONF_PAIR specifying the name of the type module.
* @param[in] rule unused.
/*
* Instantiate the master io submodule
*/
- return fr_master_app_io.common.instantiate(MODULE_INST_CTX(inst->io.dl_inst));
+ return fr_master_app_io.common.instantiate(MODULE_INST_CTX(inst->io.mi));
}
/*
* We will need this for dynamic clients and connected sockets.
*/
- inst->io.dl_inst = dl_module_instance_by_data(inst);
- fr_assert(inst != NULL);
+ inst->io.mi = mctx->inst;
/*
* Bootstrap the master IO handler.
*/
- return fr_master_app_io.common.bootstrap(MODULE_INST_CTX(inst->io.dl_inst));
+ return fr_master_app_io.common.bootstrap(MODULE_INST_CTX(inst->io.mi));
}
/** Get the authentication vector.
{ NULL }
};
-/** Wrapper around dl_instance which translates the packet-type into a submodule name
+/** Translates the packet-type into a submodule name
*
* If we found a Packet-Type = Authentication-Start CONF_PAIR for example, here's we'd load
* the proto_tacacs_auth module.
*
* @param[in] ctx to allocate data in (instance of proto_tacacs).
- * @param[out] out Where to write a dl_module_inst_t containing the module handle and instance.
+ * @param[out] out Where to write a module_instance_t containing the module handle and instance.
* @param[in] parent Base structure address.
* @param[in] ci #CONF_PAIR specifying the name of the type module.
* @param[in] rule unused.
/*
* Instantiate the master io submodule
*/
- return fr_master_app_io.common.instantiate(MODULE_INST_CTX(inst->io.dl_inst));
+ return fr_master_app_io.common.instantiate(MODULE_INST_CTX(inst->io.mi));
}
/*
* We will need this for dynamic clients and connected sockets.
*/
- inst->io.dl_inst = dl_module_instance_by_data(inst);
- fr_assert(inst != NULL);
+ inst->io.mi = mctx->inst;
/*
* Bootstrap the master IO handler.
*/
- return fr_master_app_io.common.bootstrap(MODULE_INST_CTX(inst->io.dl_inst));
+ return fr_master_app_io.common.bootstrap(MODULE_INST_CTX(inst->io.mi));
}
static int mod_load(void)
{ NULL }
};
-/** Wrapper around dl_instance which translates the packet-type into a submodule name
+/** Translates the packet-type into a submodule name
*
* @param[in] ctx to allocate data in (instance of proto_vmps).
- * @param[out] out Where to write a dl_module_inst_t containing the module handle and instance.
+ * @param[out] out Where to write a module_instance_t containing the module handle and instance.
* @param[in] parent Base structure address.
* @param[in] ci #CONF_PAIR specifying the name of the type module.
* @param[in] rule unused.
/*
* Instantiate the master io submodule
*/
- return fr_master_app_io.common.instantiate(MODULE_INST_CTX(inst->io.dl_inst));
+ return fr_master_app_io.common.instantiate(MODULE_INST_CTX(inst->io.mi));
}
/*
* We will need this for dynamic clients and connected sockets.
*/
- inst->io.dl_inst = dl_module_instance_by_data(inst);
- fr_assert(inst != NULL);
+ inst->io.mi = mctx->inst;
/*
* Bootstrap the master IO handler.
*/
- return fr_master_app_io.common.bootstrap(MODULE_INST_CTX(inst->io.dl_inst));
+ return fr_master_app_io.common.bootstrap(MODULE_INST_CTX(inst->io.mi));
}
static int mod_load(void)
* function, depending on whether the driver calls a custom parsing function.
*/
if (unlikely((ret = func(ctx, &key_tmpl, t_rules, ci, section_name1, section_name2,
- inst->driver_submodule->dl_inst->data, rule)) < 0)) return ret;
+ inst->driver_submodule->data, rule)) < 0)) return ret;
*((tmpl_t **)out) = key_tmpl;
/*
return 0;
}
- return inst->driver->acquire(out, &inst->config, inst->driver_submodule->dl_inst->data, request);
+ return inst->driver->acquire(out, &inst->config, inst->driver_submodule->data, request);
}
/** Release a handle we previously acquired
if (!inst->driver->release) return;
if (!handle || !*handle) return;
- inst->driver->release(&inst->config, inst->driver_submodule->dl_inst->data, request, *handle);
+ inst->driver->release(&inst->config, inst->driver_submodule->data, request, *handle);
*handle = NULL;
}
{
fr_assert(inst->driver->reconnect);
- return inst->driver->reconnect(handle, &inst->config, inst->driver_submodule->dl_inst->data, request);
+ return inst->driver->reconnect(handle, &inst->config, inst->driver_submodule->data, request);
}
/** Allocate a cache entry
*/
static rlm_cache_entry_t *cache_alloc(rlm_cache_t const *inst, request_t *request)
{
- if (inst->driver->alloc) return inst->driver->alloc(&inst->config, inst->driver_submodule->dl_inst->data, request);
+ if (inst->driver->alloc) return inst->driver->alloc(&inst->config, inst->driver_submodule->data, request);
return talloc_zero(NULL, rlm_cache_entry_t);
}
*out = NULL;
for (;;) {
- ret = inst->driver->find(&c, &inst->config, inst->driver_submodule->dl_inst->data, request, *handle, key);
+ ret = inst->driver->find(&c, &inst->config, inst->driver_submodule->data, request, *handle, key);
switch (ret) {
case CACHE_RECONNECT:
RDEBUG2("Reconnecting...");
fr_box_time(request->packet->timestamp));
expired:
- inst->driver->expire(&inst->config, inst->driver_submodule->dl_inst->data, request, handle, key);
+ inst->driver->expire(&inst->config, inst->driver_submodule->data, request, handle, key);
cache_free(inst, &c);
RETURN_MODULE_NOTFOUND; /* Couldn't find a non-expired entry */
}
rlm_cache_handle_t **handle, fr_value_box_t const *key)
{
RDEBUG2("Expiring cache entry");
- for (;;) switch (inst->driver->expire(&inst->config, inst->driver_submodule->dl_inst->data, request, *handle, key)) {
+ for (;;) switch (inst->driver->expire(&inst->config, inst->driver_submodule->data, request, *handle, key)) {
case CACHE_RECONNECT:
if (cache_reconnect(handle, inst, request) == 0) continue;
FALL_THROUGH;
TALLOC_CTX *pool;
if ((inst->config.max_entries > 0) && inst->driver->count &&
- (inst->driver->count(&inst->config, inst->driver_submodule->dl_inst->data, request, handle) > inst->config.max_entries)) {
+ (inst->driver->count(&inst->config, inst->driver_submodule->data, request, handle) > inst->config.max_entries)) {
RWDEBUG("Cache is full: %d entries", inst->config.max_entries);
RETURN_MODULE_FAIL;
}
for (;;) {
cache_status_t ret;
- ret = inst->driver->insert(&inst->config, inst->driver_submodule->dl_inst->data, request, *handle, c);
+ ret = inst->driver->insert(&inst->config, inst->driver_submodule->data, request, *handle, c);
switch (ret) {
case CACHE_RECONNECT:
if (cache_reconnect(handle, inst, request) == 0) continue;
if (!inst->driver->set_ttl) for (;;) {
cache_status_t ret;
- ret = inst->driver->insert(&inst->config, inst->driver_submodule->dl_inst->data, request, *handle, c);
+ ret = inst->driver->insert(&inst->config, inst->driver_submodule->data, request, *handle, c);
switch (ret) {
case CACHE_RECONNECT:
if (cache_reconnect(handle, inst, request) == 0) continue;
for (;;) {
cache_status_t ret;
- ret = inst->driver->set_ttl(&inst->config, inst->driver_submodule->dl_inst->data, request, *handle, c);
+ ret = inst->driver->set_ttl(&inst->config, inst->driver_submodule->data, request, *handle, c);
switch (ret) {
case CACHE_RECONNECT:
if (cache_reconnect(handle, inst, request) == 0) continue;
rlm_cache_t *inst = talloc_get_type_abort(mctx->inst->data, rlm_cache_t );
xlat_t *xlat;
- inst->driver = (rlm_cache_driver_t const *)inst->driver_submodule->dl_inst->module->common;
+ inst->driver = (rlm_cache_driver_t const *)inst->driver_submodule->module->exported;
/*
* Non optional fields and callbacks
static unlang_action_t mod_authenticate(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request) CC_HINT(nonnull);
static unlang_action_t mod_authorize(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request) CC_HINT(nonnull);
-/** Wrapper around dl_instance which loads submodules based on type = foo pairs
+/** Loads submodules based on type = foo pairs
*
* @param[in] ctx to allocate data in (instance of rlm_eap_t).
* @param[out] out Where to write child conf section to.
CONF_SECTION *eap_cs = cf_item_to_section(cf_parent(ci));
module_inst_ctx_t *mctx = MODULE_INST_CTX(
- ((dl_module_inst_t *)cf_data_value(cf_data_find(eap_cs,
- dl_module_inst_t, "rlm_eap"))));
+ ((module_instance_t *)cf_data_value(cf_data_find(eap_cs,
+ module_instance_t, "rlm_eap"))));
WARN("Ignoring EAP method %s because we don't have OpenSSL support", name);
}
return 0;
(rlm_eap_submodule_t const *)inst->type_identity_submodule[i]->module;
eap_type_t ret;
- ret = submodule->type_identity(inst->type_identity_submodule[i]->dl_inst->data,
+ ret = submodule->type_identity(inst->type_identity_submodule[i]->data,
eap_session->identity,
talloc_array_length(eap_session->identity) - 1);
if (ret != FR_EAP_METHOD_INVALID) {
if (!submodule_inst) continue; /* Skipped as we don't have SSL support */
- submodule = (rlm_eap_submodule_t const *)submodule_inst->dl_inst->module->common;
+ submodule = (rlm_eap_submodule_t const *)submodule_inst->module->exported;
/*
* Add the methods the submodule provides
* Check for duplicates
*/
if (inst->methods[method].submodule) {
- CONF_SECTION *conf = inst->methods[method].submodule_inst->dl_inst->conf;
+ CONF_SECTION *conf = inst->methods[method].submodule_inst->conf;
- cf_log_err(submodule_inst->dl_inst->conf,
+ cf_log_err(submodule_inst->conf,
"Duplicate EAP-Type %s. Conflicting entry %s[%u]",
eap_type2name(method),
cf_filename(conf), cf_lineno(conf));
*
*/
typedef struct {
- dl_module_inst_t const *dlinst;
+ module_instance_t const *dlinst;
rlm_ldap_t const *inst;
fr_ldap_map_exp_t expanded;
fr_ldap_query_t *query;
if (!io->signal) return;
- io->signal(MODULE_CTX(inst->io_submodule->dl_inst,
+ io->signal(MODULE_CTX(inst->io_submodule,
module_thread(inst->io_submodule)->data, mctx->env_data,
mctx->rctx), request, action);
}
* return another code which indicates what happened to
* the request...
*/
- ua = inst->io->enqueue(&rcode, &rctx, inst->io_submodule->dl_inst->data,
+ ua = inst->io->enqueue(&rcode, &rctx, inst->io_submodule->data,
module_thread(inst->io_submodule)->data, request);
if (ua != UNLANG_ACTION_YIELD) {
fr_assert(rctx == NULL);
*/
void rest_io_xlat_signal(xlat_ctx_t const *xctx, request_t *request, fr_signal_t action)
{
- rlm_rest_t *mod_inst = talloc_get_type_abort(xctx->mctx->inst->data, rlm_rest_t);
rlm_rest_thread_t *t = talloc_get_type_abort(xctx->mctx->thread, rlm_rest_thread_t);
rlm_rest_xlat_rctx_t *our_rctx = talloc_get_type_abort(xctx->rctx, rlm_rest_xlat_rctx_t);
fr_curl_io_request_t *randle = talloc_get_type_abort(our_rctx->handle, fr_curl_io_request_t);
- rest_io_module_signal(MODULE_CTX(dl_module_instance_by_data(mod_inst),
+ rest_io_module_signal(MODULE_CTX(xctx->mctx->inst,
t,
xctx->mctx->env_data,
randle),
*
* @todo We could extract the User-Name and password from the URL string.
*/
- ret = rest_request_config(MODULE_CTX(dl_module_instance_by_data(inst), t, xctx->env_data, NULL),
+ ret = rest_request_config(MODULE_CTX(xctx->mctx->inst, t, xctx->env_data, NULL),
section, request, randle, section->request.method,
section->request.body,
uri_vb->vb_strvalue, in_vb ? in_vb->vb_strvalue : NULL);
static sql_rcode_t sql_socket_init(rlm_sql_handle_t *handle, rlm_sql_config_t const *config, fr_time_delta_t timeout)
{
rlm_sql_cassandra_conn_t *conn;
- rlm_sql_cassandra_t *inst = talloc_get_type_abort(handle->inst->driver_submodule->dl_inst->data, rlm_sql_cassandra_t);
+ rlm_sql_cassandra_t *inst = talloc_get_type_abort(handle->inst->driver_submodule->data, rlm_sql_cassandra_t);
MEM(conn = handle->conn = talloc_zero(handle, rlm_sql_cassandra_conn_t));
talloc_set_destructor(conn, _sql_socket_destructor);
static sql_rcode_t sql_query(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config, char const *query)
{
rlm_sql_cassandra_conn_t *conn = handle->conn;
- rlm_sql_cassandra_t *inst = talloc_get_type_abort(handle->inst->driver_submodule->dl_inst->data, rlm_sql_cassandra_t);
+ rlm_sql_cassandra_t *inst = talloc_get_type_abort(handle->inst->driver_submodule->data, rlm_sql_cassandra_t);
CassStatement *statement;
CassFuture *future;
static sql_rcode_t sql_socket_init(rlm_sql_handle_t *handle, rlm_sql_config_t const *config, fr_time_delta_t timeout)
{
- rlm_sql_mysql_t *inst = talloc_get_type_abort(handle->inst->driver_submodule->dl_inst->data, rlm_sql_mysql_t);
+ rlm_sql_mysql_t *inst = talloc_get_type_abort(handle->inst->driver_submodule->data, rlm_sql_mysql_t);
rlm_sql_mysql_conn_t *conn;
unsigned int connect_timeout = (unsigned int)fr_time_delta_to_sec(timeout);
static size_t sql_error(TALLOC_CTX *ctx, sql_log_entry_t out[], size_t outlen,
rlm_sql_handle_t *handle, rlm_sql_config_t const *config)
{
- rlm_sql_mysql_t *inst = talloc_get_type_abort(handle->inst->driver_submodule->dl_inst->data, rlm_sql_mysql_t);
+ rlm_sql_mysql_t *inst = talloc_get_type_abort(handle->inst->driver_submodule->data, rlm_sql_mysql_t);
rlm_sql_mysql_conn_t *conn = talloc_get_type_abort(handle->conn, rlm_sql_mysql_conn_t);
char const *error;
size_t i = 0;
{
char errbuff[512];
- rlm_sql_oracle_t *inst = talloc_get_type_abort(handle->inst->driver_submodule->dl_inst->data, rlm_sql_oracle_t);
+ rlm_sql_oracle_t *inst = talloc_get_type_abort(handle->inst->driver_submodule->data, rlm_sql_oracle_t);
rlm_sql_oracle_conn_t *conn;
MEM(conn = handle->conn = talloc_zero(handle, rlm_sql_oracle_conn_t));
static int CC_HINT(nonnull) sql_socket_init(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config,
UNUSED fr_time_delta_t timeout)
{
- rlm_sql_postgresql_t *inst = talloc_get_type_abort(handle->inst->driver_submodule->dl_inst->data, rlm_sql_postgresql_t);
+ rlm_sql_postgresql_t *inst = talloc_get_type_abort(handle->inst->driver_submodule->data, rlm_sql_postgresql_t);
rlm_sql_postgres_conn_t *conn;
MEM(conn = handle->conn = talloc_zero(handle, rlm_sql_postgres_conn_t));
char const *query)
{
rlm_sql_postgres_conn_t *conn = handle->conn;
- rlm_sql_postgresql_t *inst = talloc_get_type_abort(handle->inst->driver_submodule->dl_inst->data, rlm_sql_postgresql_t);
+ rlm_sql_postgresql_t *inst = talloc_get_type_abort(handle->inst->driver_submodule->data, rlm_sql_postgresql_t);
fr_time_delta_t timeout = config->query_timeout;
fr_time_t start;
int sockfd;
UNUSED fr_time_delta_t timeout)
{
rlm_sql_sqlite_conn_t *conn;
- rlm_sql_sqlite_t *inst = talloc_get_type_abort(handle->inst->driver_submodule->dl_inst->data, rlm_sql_sqlite_t);
+ rlm_sql_sqlite_t *inst = talloc_get_type_abort(handle->inst->driver_submodule->data, rlm_sql_sqlite_t);
int status;
rlm_sql_escape_uctx_t *uctx;
inst->name = mctx->inst->name; /* Need this for functions in sql.c */
- inst->driver = (rlm_sql_driver_t const *)inst->driver_submodule->module; /* Public symbol exported by the submodule */
+ inst->driver = (rlm_sql_driver_t const *)inst->driver_submodule->module->exported; /* Public symbol exported by the submodule */
/*
* Register the group comparison attribute
return -1;
}
- if (!talloc_get_type(sql_inst->dl_inst->data, rlm_sql_t)) {
+ if (!talloc_get_type(sql_inst->data, rlm_sql_t)) {
cf_log_err(conf, "\"%s\" is not an instance of rlm_sql", inst->sql_name);
return -1;
}
return -1;
}
- inst->sql = (rlm_sql_t *) sql->dl_inst->data;
+ inst->sql = (rlm_sql_t *) sql->data;
if (strcmp(talloc_get_name(inst->sql), "rlm_sql_t") != 0) {
cf_log_err(conf, "Module \"%s\" is not an instance of the rlm_sql module",
*/
sql_inst = module_rlm_by_name(NULL, inst->sql_name);
if (!sql_inst) return -1;
- sql = talloc_get_type_abort(sql_inst->dl_inst->data, rlm_sql_t);
+ sql = talloc_get_type_abort(sql_inst->data, rlm_sql_t);
/*
* Set the sql module instance data as the uctx for escaping
if (!io->signal) return;
- io->signal(MODULE_CTX(inst->io_submodule->dl_inst,
+ io->signal(MODULE_CTX(inst->io_submodule,
module_thread(inst->io_submodule)->data, mctx->env_data,
mctx->rctx), request, action);
}
* return another code which indicates what happened to
* the request...
*/
- ua = inst->io->enqueue(&rcode, &rctx, inst->io_submodule->dl_inst->data,
+ ua = inst->io->enqueue(&rcode, &rctx, inst->io_submodule->data,
module_thread(inst->io_submodule)->data, request);
if (ua != UNLANG_ACTION_YIELD) {
fr_assert(rctx == NULL);
fr_proto_lib_t const libfreeradius_ethernet = {
.magic = MODULE_MAGIC_INIT,
.name = "ethernet",
- .inst_size = sizeof(fr_ethernet_proto_ctx_t),
-
.opt_group = PROTO_OPT_GROUP_CUSTOM | PROTO_OPT_GROUP_L2,
.decode = fr_ethernet_decode,