terom@54: #ifndef MODULE_H terom@54: #define MODULE_H terom@54: terom@54: /** terom@54: * @file terom@54: * terom@55: * Dynamically loadable modules for use with nexus. terom@55: * terom@55: * The modules are loaded using dlopen(), and hence should be standard dynamic libraries. Module initialization happens terom@55: * using a module_init_func_t named "_init", which should return some kind of context pointer, which can later be terom@55: * used to perform other operations on the module. terom@54: */ terom@54: #include "nexus.h" terom@54: #include "error.h" terom@54: terom@54: #include terom@54: terom@54: /** terom@54: * Information required to load/identify a module. terom@54: */ terom@54: struct module_info { terom@54: /** Human-readable name */ terom@54: const char *name; terom@54: terom@54: /** Filesystem path to the .so */ terom@54: const char *path; terom@54: }; terom@54: terom@54: /** terom@57: * A module's behaviour is defined as a set of function pointers, which is dynamically resolved from the module DSO, terom@57: * using the _funcs symbol. terom@57: */ terom@57: struct module_funcs { terom@57: /** terom@57: * Initialize the module, returning an opaque context pointer that is stored in the module state, and supplied for terom@57: * subsequent calls. The supplied nexus arg can be used to access the global state. terom@57: * terom@57: * @param nexus a pointer to the nexus struct containing the global state terom@57: * @param ctx_ptr the context pointer should be returned via this terom@57: * @param err returned error info terom@57: */ terom@57: err_t (*init) (struct nexus *nexus, void **ctx_ptr, struct error_info *err); terom@57: terom@57: /** terom@57: * Set a configuration option with the given name and value, given by the user. Configuration settings are not terom@57: * regarded as unique-per-name, but rather, several invocations of 'conf' with the same name and different values terom@57: * could set up a multitude of things. terom@57: * terom@66: * The given value is either a NUL-terminated string value (which may be mutated, using e.g. strsep), or NULL if terom@66: * no value was given (flag option). terom@57: * terom@57: * @param ctx the module's context pointer as returned by init terom@57: * @param name the name of the configuration setting terom@57: * @param value the value of the configuration setting terom@57: * @param err returned error info terom@57: */ terom@57: err_t (*conf) (void *ctx, const char *name, char *value, struct error_info *err); terom@57: }; terom@57: terom@57: /** terom@54: * A loaded module. terom@54: */ terom@54: struct module { terom@54: /** The identifying info for the module */ terom@54: struct module_info info; terom@54: terom@55: /** The dlopen handle */ terom@55: void *handle; terom@55: terom@57: /** The resolved function table */ terom@57: struct module_funcs *funcs; terom@57: terom@54: /** The module context object */ terom@54: void *ctx; terom@54: terom@54: /** Our entry in the list of modules */ terom@55: TAILQ_ENTRY(module) modules_list; terom@54: }; terom@54: terom@54: /** terom@54: * A set of loaded modules, and functionality to load more terom@54: */ terom@54: struct modules { terom@54: /** The nexus in use */ terom@54: struct nexus *nexus; terom@54: terom@54: /** List of loaded modules */ terom@55: TAILQ_HEAD(module_ctx_modules, module) list; terom@55: }; terom@55: terom@55: /** terom@55: * Possible error codes terom@55: */ terom@55: enum module_error_code { terom@55: _ERR_MODULE_BEGIN = _ERR_MODULE, terom@55: terom@55: ERR_MODULE_OPEN, ///< dlopen() failed terom@55: ERR_MODULE_NAME, ///< invalid module_info.name terom@55: ERR_MODULE_SYM, ///< invalid symbol terom@55: ERR_MODULE_INIT_FUNC, ///< invalid module_init_func_t terom@56: ERR_MODULE_CONF, ///< value error in configuration data terom@54: }; terom@54: terom@55: terom@55: /** terom@55: * Maximum length of a module name terom@55: */ terom@55: #define MODULE_NAME_MAX 24 terom@55: terom@55: /** terom@55: * Maximum length of module symbol suffix terom@55: */ terom@55: #define MODULE_SUFFIX_MAX 16 terom@55: terom@55: /** terom@55: * Maximum length of symbol name name, including terminating NUL terom@55: */ terom@55: #define MODULE_SYMBOL_MAX (MODULE_NAME_MAX + 1 + MODULE_SUFFIX_MAX + 1) terom@54: terom@54: /** terom@54: * Create a new modules state terom@54: */ terom@54: err_t modules_create (struct modules **modules_ptr, struct nexus *nexus); terom@54: terom@54: /** terom@55: * Load a new module terom@65: * terom@65: * @param modules the module-loading context terom@65: * @param module_ptr return the new module via this, if not NULL terom@65: * @param info the info required to identify and load the module terom@65: * @param err return error info terom@54: */ terom@56: err_t module_load (struct modules *modules, struct module **module_ptr, const struct module_info *info, struct error_info *err); terom@55: terom@55: /** terom@66: * Lookup a module by name terom@66: * terom@66: * @param modules the modules state terom@66: * @param name the module name to get terom@66: * @return the module struct, or NULL if not found terom@66: */ terom@66: struct module* module_get (struct modules *modules, const char *name); terom@66: terom@66: /** terom@55: * Set a module configuration option terom@55: */ terom@56: err_t module_conf (struct module *module, const char *name, char *value, struct error_info *err); terom@54: terom@54: /** terom@54: * Unload a module terom@55: * terom@55: * XXX: not implemented terom@54: */ terom@54: err_t module_unload (struct module *module); terom@54: terom@54: #endif