{
int ret = engine_pcall(L, argc);
if (ret != 0) {
- fprintf(stderr, "error: %s\n", lua_tostring(L, -1));
+ kr_log_error("error: %s\n", lua_tostring(L, -1));
}
/* Clear the stack, there may be event a/o enything returned */
lua_settop(L, 0);
#include <contrib/cleanup.h>
#include <ccan/json/json.h>
#include <ccan/asprintf/asprintf.h>
+#include <dlfcn.h>
#include <uv.h>
#include <unistd.h>
#include <grp.h>
/** Unregister a (found) module */
static void engine_unload(struct engine *engine, struct kr_module *module)
{
- auto_free char *name = strdup(module->name);
- kr_module_unload(module);
+ auto_free char *name = module->name ? strdup(module->name) : NULL;
+ kr_module_unload(module); /* beware: lua/C mix, could be confusing */
/* Clear in Lua world, but not for embedded modules ('cache' in particular). */
if (name && !kr_module_get_embedded(name)) {
lua_pushnil(engine->L);
int engine_register(struct engine *engine, const char *name, const char *precedence, const char* ref)
{
if (engine == NULL || name == NULL) {
+ assert(!EINVAL);
return kr_error(EINVAL);
}
/* Make sure module is unloaded */
if (!module) {
return kr_error(ENOMEM);
}
- module->data = engine;
- /* TODO: tidy and comment this section. */
+ module->data = engine; /*< some outside modules may still use this value */
+
int ret = kr_module_load(module, name, LIBDIR "/kres_modules");
- if (ret == kr_ok()) {
- lua_getglobal(engine->L, "modules_create_table_for_c");
- lua_pushpointer(engine->L, module);
- if (engine_pcall(engine->L, 1) != 0) {
- lua_pop(engine->L, 1);
+ if (ret == 0) {
+ /* We have a C module, loaded and init() was called.
+ * Now we need to prepare the lua side. */
+ lua_State *L = engine->L;
+ lua_getglobal(L, "modules_create_table_for_c");
+ lua_pushpointer(L, module);
+ if (lua_isnil(L, -2)) {
+ /* When loading the three embedded modules, we don't
+ * have the "modules_*" lua function yet, but fortunately
+ * we don't need it there. Let's just check they're embedded.
+ * TODO: solve this better *without* breaking stuff. */
+ lua_pop(L, 2);
+ if (module->lib != RTLD_DEFAULT) {
+ ret = kr_error(1);
+ lua_pushliteral(L, "missing modules_create_table_for_c()");
+ }
+ } else {
+ ret = engine_pcall(L, 1);
}
- }
- /* Load Lua module if not a binary */
- if (ret == kr_error(ENOENT)) {
+ if (ret) {
+ kr_log_error("[system] internal error when loading C module %s: %s\n",
+ module->name, lua_tostring(L, -1));
+ lua_pop(L, 1);
+ assert(false); /* probably not critical, but weird */
+ }
+
+ } else if (ret == kr_error(ENOENT)) {
+ /* No luck with C module, so try to load and .init() lua module. */
ret = ffimodule_register_lua(engine, module, name);
+ if (ret != 0) {
+ kr_log_error("[system] failed to load module '%s'\n", name);
+ }
+
} else if (ret == kr_error(ENOTSUP)) {
/* Print a more helpful message when module is linked against an old resolver ABI. */
- fprintf(stderr, "[system] module '%s' links to unsupported ABI, please rebuild it\n", name);
+ kr_log_error("[system] module '%s' links to unsupported ABI, please rebuild it\n", name);
}
+
if (ret != 0) {
- free(module);
+ engine_unload(engine, module);
return ret;
}
+ /* Push to the right place in engine->modules */
if (array_push(engine->modules, module) < 0) {
engine_unload(engine, module);
return kr_error(ENOMEM);
}
- /* Evaluate precedence operator */
if (precedence) {
struct kr_module **arr = mod_list->at;
size_t emplacement = mod_list->len;
/** Lua registry indices for functions that wrap layer callbacks (shared by all lua modules). */
static int l_ffi_wrap_slots[SLOT_count] = { 0 };
-/** @internal Helper for retrieving the right function entrypoint. */
-static inline lua_State *l_ffi_preface(struct kr_module *module, const char *call) {
- lua_State *L = module->lib;
- lua_getglobal(L, module->name);
- lua_getfield(L, -1, call);
- lua_remove(L, -2);
- if (lua_isnil(L, -1)) {
- lua_pop(L, 1);
- return NULL;
- }
- lua_pushlightuserdata(L, module);
- return L;
-}
-
/** @internal Continue with coroutine. */
static void l_ffi_resume_cb(uv_idle_t *check)
{
if (lua_isnumber(L, -1)) { /* Return code */
status = lua_tointeger(L, -1);
} else if (lua_isthread(L, -1)) { /* Continuations */
+ /* TODO: unused, possibly in a bad shape. Meant KR_STATE_YIELD? */
+ assert(!ENOTSUP);
status = l_ffi_defer(lua_tothread(L, -1));
}
lua_pop(L, 1);
return status;
}
-static int l_ffi_init(struct kr_module *module)
+/** Common part of calling modname.(de)init in lua.
+ * The function to call should be on top of the stack and it gets popped. */
+static int l_ffi_modcb(lua_State *L, struct kr_module *module)
{
- lua_State *L = l_ffi_preface(module, "init");
- if (!L) {
- return 0;
+ if (lua_isnil(L, -1)) {
+ lua_pop(L, 1); /* .(de)init == nil, maybe even the module table doesn't exist */
+ return kr_ok();
}
- return l_ffi_call_mod(L, 1);
+ lua_getglobal(L, "modules_ffi_wrap_modcb");
+ lua_insert(L, -2); /* swap with .(de)init */
+ lua_pushpointer(L, module);
+ if (lua_pcall(L, 2, 0, 0) == 0)
+ return kr_ok();
+ kr_log_error("error: %s\n", lua_tostring(L, -1));
+ lua_pop(L, 1);
+ return kr_error(1);
}
static int l_ffi_deinit(struct kr_module *module)
{
- /* Deinit the module in Lua (if possible) */
- int ret = 0;
- lua_State *L = module->lib;
- if (l_ffi_preface(module, "deinit")) {
- ret = l_ffi_call_mod(L, 1);
- }
- module->lib = NULL;
+ /* Call .deinit(), if it exists. */
+ lua_State *L = the_worker->engine->L;
+ lua_getglobal(L, module->name);
+ lua_getfield(L, -1, "deinit");
+ const int ret = l_ffi_modcb(L, module);
+ lua_pop(L, 1); /* the module's table */
+
/* Free the layer API wrapper (unconst it) */
kr_layer_api_t* api = module->data;
if (!api) {
/* Create FFI module with trampolined functions. */
memset(module, 0, sizeof(*module));
module->name = strdup(name);
- module->init = &l_ffi_init;
module->deinit = &l_ffi_deinit;
/* Bake layer API if defined in module */
lua_getfield(L, -1, "layer");
/* most likely not needed, but compatibility for now */
module->data = (void *)module->layer;
}
- module->lib = L;
- lua_pop(L, 2); /* Clear the layer + module global */
- if (module->init) {
- return module->init(module);
- }
- return kr_ok();
+ lua_pop(L, 1); /* .layer table */
+
+ /* Now call .init(), if it exists. */
+ lua_getfield(L, -1, "init");
+ const int ret = l_ffi_modcb(L, module);
+ lua_pop(L, 1); /* the module's table */
+ return ret;
}
local ctx = ffi.cast('kr_layer_t **', ctx_udata)[0]
return layer_cb(ctx.state, ctx.req, ctx.pkt, ctx.dst, ctx.is_stream)
end
+modules_ffi_wrap_modcb = function (cb, kr_module_ud) -- this one isn't for layer
+ local kr_module = ffi.cast('struct kr_module **', kr_module_ud)[0]
+ return cb(kr_module)
+end
cache.clear = function (name, exact_name, rr_type, chunk_size, callback, prev_state)
if name == nil or (name == '.' and not exact_name) then
struct kr_module {
char *name;
- /** Constructor. Called after loading the module. @return error code. */
+ /** Constructor. Called after loading the module. @return error code.
+ * Lua modules: not populated, called via lua directly. */
int (*init)(struct kr_module *self);
+
/** Destructor. Called before unloading the module. @return error code. */
int (*deinit)(struct kr_module *self);
- /** Configure with encoded JSON (NULL if missing). @return error code. */
+
+ /** Configure with encoded JSON (NULL if missing). @return error code.
+ * Lua modules: not used and not useful from C.
+ * When called from lua, input is JSON, like for kr_prop_cb. */
int (*config)(struct kr_module *self, const char *input);
- /** Packet processing API specs. May be NULL. See docs on that type. */
+
+ /** Packet processing API specs. May be NULL. See docs on that type.
+ * Owned by the module code. */
const kr_layer_api_t *layer;
- /** List of properties. May be NULL. Terminated by { NULL, NULL, NULL }. */
+
+ /** List of properties. May be NULL. Terminated by { NULL, NULL, NULL }.
+ * Lua modules: not used and not useful. */
const struct kr_prop *props;
- void *lib; /**< Shared library handle or RTLD_DEFAULT */
- void *data; /**< Custom data context. */
+ /** dlopen() handle; RTLD_DEFAULT for embedded modules; NULL for lua modules. */
+ void *lib;
+ void *data; /**< Custom data context. */
};
/**
* @param env pointer to the lua engine, i.e. struct engine *env (TODO: explicit type)
* @param input parameter (NULL if missing/nil on lua level)
* @return a free-form JSON output (malloc-ated)
- * @note see l_trampoline() implementation for details about the input/output conversion.
+ * @note see modules_create_table_for_c() implementation for details
+ * about the input/output conversion.
*/
typedef char *(kr_prop_cb)(void *env, struct kr_module *self, const char *input);
/**
- * Load a C module instance into memory.
+ * Load a C module instance into memory. And call its init().
*
- * @param module module structure
+ * @param module module structure. Will be overwritten except for ->data on success.
* @param name module name
* @param path module search path
* @return 0 or an error
* Unload module instance.
*
* @param module module structure
+ * @note currently used even for lua modules
*/
KR_EXPORT
void kr_module_unload(struct kr_module *module);