...when making calls from lua to C modules; use luaJIT FFI instead.
This eliminates some cases of lua_pushlightuserdata().
'quit',
'resolve',
'ta_update',
+ 'fromjson',
'todname',
'tojson',
'user',
* Global bindings.
*/
-/** Register module callback into Lua world. */
-#define REGISTER_MODULE_CALL(L, module, cb, name) do { \
- lua_pushlightuserdata((L), (module)); \
- lua_pushlightuserdata((L), (cb)); \
- lua_pushcclosure((L), l_trampoline, 2); \
- lua_setfield((L), -2, (name)); \
- } while (0)
/** Print help and available commands. */
static int l_help(lua_State *L)
#undef expr_checked
-/** Trampoline function for module properties. */
-static int l_trampoline(lua_State *L)
-{
- struct kr_module *module = lua_touserdata(L, lua_upvalueindex(1));
- void* callback = lua_touserdata(L, lua_upvalueindex(2));
- struct engine *engine = engine_luaget(L);
- if (!module)
- lua_error_p(L, "module closure missing upvalue");
-
- /* Now we only have property callback or config,
- * if we expand the callables, we might need a callback_type.
- */
- const char *args = NULL;
- auto_free char *cleanup_args = NULL;
- if (lua_gettop(L) > 0) {
- if (lua_istable(L, 1) || lua_isboolean(L, 1)) {
- cleanup_args = l_pack_json(L, 1);
- args = cleanup_args;
- } else {
- args = lua_tostring(L, 1);
- }
- }
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wpedantic" /* void* vs. function pointer */
- if (callback == module->config) {
- module->config(module, args);
- } else {
- kr_prop_cb *prop = (kr_prop_cb *)callback;
- auto_free char *ret = prop(engine, module, args);
- if (!ret) { /* No results */
- return 0;
- }
- JsonNode *root_node = json_decode(ret);
- if (root_node) {
- l_unpack_json(L, root_node);
- } else {
- lua_pushstring(L, ret);
- }
- json_delete(root_node);
- return 1;
- }
- #pragma GCC diagnostic pop
-
- /* No results */
- return 0;
-}
-
/*
* Engine API.
*/
uv_stop(uv_default_loop());
}
-/** Register module properties in Lua environment, if any. */
-static int register_properties(struct engine *engine, struct kr_module *module)
-{
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wpedantic" /* casts in lua_pushlightuserdata() */
- if (!module->config && !module->props) {
- return kr_ok();
- }
- lua_newtable(engine->L);
- if (module->config != NULL) {
- REGISTER_MODULE_CALL(engine->L, module, module->config, "config");
- }
-
- for (const struct kr_prop *p = module->props; p && p->name; ++p) {
- if (p->cb != NULL) {
- REGISTER_MODULE_CALL(engine->L, module, p->cb, p->name);
- }
- }
- lua_setglobal(engine->L, module->name);
- #pragma GCC diagnostic pop
-
- /* Register module in Lua env */
- lua_getglobal(engine->L, "modules_register");
- lua_getglobal(engine->L, module->name);
- if (engine_pcall(engine->L, 1) != 0) {
- lua_pop(engine->L, 1);
- }
-
- return kr_ok();
-}
-
/** @internal Find matching module */
static size_t module_find(module_array_t *mod_list, const char *name)
{
return kr_error(ENOMEM);
}
module->data = engine;
+ /* TODO: tidy and comment this section. */
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);
+ }
+ }
/* Load Lua module if not a binary */
if (ret == kr_error(ENOENT)) {
ret = ffimodule_register_lua(engine, module, name);
free(module);
return ret;
}
+
if (array_push(engine->modules, module) < 0) {
engine_unload(engine, module);
return kr_error(ENOMEM);
}
}
- return register_properties(engine, module);
+ return kr_ok();
}
int engine_unregister(struct engine *engine, const char *name)
knot_rdataset_t rrs;
void *additional;
} knot_rrset_t;
+
+struct kr_module;
+typedef char *(kr_prop_cb)(void *, struct kr_module *, const char *);
+struct kr_layer;
typedef struct knot_pkt knot_pkt_t;
typedef struct {
uint8_t *ptr[15];
void *root;
struct knot_mm *pool;
} map_t;
+typedef struct trie trie_t;
struct kr_qflags {
_Bool NO_MINIMIZE : 1;
_Bool NO_THROTTLE : 1;
size_t len;
size_t cap;
} ranked_rr_array_t;
-typedef struct trie trie_t;
struct kr_zonecut {
knot_dname_t *name;
knot_rrset_t *key;
struct timeval checkpoint_walltime;
uint64_t checkpoint_monotime;
};
+typedef struct kr_layer kr_layer_t;
+struct kr_layer_api {
+ int (*begin)(kr_layer_t *);
+ int (*reset)(kr_layer_t *);
+ int (*finish)(kr_layer_t *);
+ int (*consume)(kr_layer_t *, knot_pkt_t *);
+ int (*produce)(kr_layer_t *, knot_pkt_t *);
+ int (*checkout)(kr_layer_t *, knot_pkt_t *, struct sockaddr *, int);
+ int (*answer_finalize)(kr_layer_t *);
+ void *data;
+ int cb_slots[];
+};
+typedef struct kr_layer_api kr_layer_api_t;
+struct kr_prop {
+ kr_prop_cb *cb;
+ const char *name;
+ const char *info;
+};
+struct kr_module {
+ char *name;
+ int (*init)(struct kr_module *);
+ int (*deinit)(struct kr_module *);
+ int (*config)(struct kr_module *, const char *);
+ const kr_layer_api_t *layer;
+ const struct kr_prop *props;
+ void *lib;
+ void *data;
+};
typedef int32_t (*kr_stale_cb)(int32_t ttl, const knot_dname_t *owner, uint16_t type,
const struct kr_query *qry);
# - you need to have debugging symbols for knot-dns and knot-resolver;
# you get those by compiling with -g; for knot-dns it might be enough
# to just install it with debugging symbols included (in your distro way)
-# - remove file ./kres-gen.lua and run make as usual
+# - run ninja kres-gen
# - the knot-dns libraries are found via pkg-config
# - you also need gdb on $PATH
# No simple way to fixup this rename in ./kres.lua AFAIK.
genResType "knot_rrset_t" | sed 's/\<owner\>/_owner/; s/\<ttl\>/_ttl/'
+printf "
+struct kr_module;
+typedef char *(kr_prop_cb)(void *, struct kr_module *, const char *);
+struct kr_layer;
+"
+
${CDEFS} ${LIBKRES} types <<-EOF
knot_pkt_t
knot_edns_options_t
struct knot_compr
knot_compr_t
struct knot_pkt
- # generics
+ # lib/generic/
map_t
+ trie_t
# libkres
struct kr_qflags
rr_array_t
struct ranked_rr_array_entry
ranked_rr_array_entry_t
ranked_rr_array_t
- trie_t
struct kr_zonecut
kr_qarray_t
struct kr_rplan
enum kr_rank
struct kr_cdb_stats
struct kr_cache
+ # lib/layer.h
+ kr_layer_t
+ struct kr_layer_api
+ kr_layer_api_t
+ # lib/module.h
+ struct kr_prop
+ struct kr_module
EOF
printf "
end
})
+-- Set up lua table for a C module. (Internal function.)
+function modules_create_table_for_c(kr_module_ud)
+ local kr_module = ffi.cast('struct kr_module **', kr_module_ud)[0]
+ --- Set up the global table named according to the module.
+ if kr_module.config == nil and kr_module.props == nil then
+ return
+ end
+ local module = {}
+ _G[ffi.string(kr_module.name)] = module
+
+ --- Construct lua functions for properties.
+ if kr_module.props ~= nil then
+ local i = 0
+ while true do
+ local prop = kr_module.props[i]
+ local cb = prop.cb
+ if cb == nil then break; end
+ module[ffi.string(prop.name)] =
+ function (arg) -- lua wrapper around kr_prop_cb function typedef
+ local arg_conv
+ if type(arg) == 'table' or type(arg) == 'boolean' then
+ arg_conv = tojson(arg)
+ elseif arg ~= nil then
+ arg_conv = tostring(arg)
+ end
+ local ret_cstr = cb(__engine, kr_module, arg_conv)
+ if ret_cstr == nil then
+ return nil
+ end
+ -- LATER(optim.): superfluous copying
+ local ret_str = ffi.string(ret_cstr)
+ -- This is a bit ugly, but the API is that invalid JSON
+ -- should be just returned as string :-(
+ local status, ret = pcall(fromjson, ret_str)
+ if not status then ret = ret_str end
+ ffi.C.free(ret_cstr)
+ return ret
+ end
+ i = i + 1
+ end
+ end
+
+ --- Construct lua function for config().
+ if kr_module.config ~= nil then
+ module.config =
+ function (arg)
+ local arg_conv
+ if type(arg) == 'table' or type(arg) == 'boolean' then
+ arg_conv = tojson(arg)
+ elseif arg ~= nil then
+ arg_conv = tostring(arg)
+ end
+ return kr_module.config(kr_module, arg_conv)
+ end
+ end
+
+ --- Add syntactic sugar for get() and set() properties.
+ --- That also "catches" any commands like `moduleName.foo = bar`.
+ setmetatable(module, {
+ __index = function (t, k)
+ local v = rawget(t, k)
+ if v then return v
+ elseif rawget(t, 'get') then return t.get(k)
+ end
+ end,
+ __newindex = function (t, k, v)
+ local old_v = rawget(t, k)
+ if not old_v and rawget(t, 'set') then
+ t.set(k..' '..v)
+ end
+ end
+ })
+end
cache.clear = function (name, exact_name, rr_type, chunk_size, callback, prev_state)
if name == nil or (name == '.' and not exact_name) then
end
})
--- Register module in Lua environment
-function modules_register(module)
- -- Syntactic sugar for get() and set() properties
- setmetatable(module, {
- __index = function (t, k)
- local v = rawget(t, k)
- if v then return v
- elseif rawget(t, 'get') then return t.get(k)
- end
- end,
- __newindex = function (t, k, v)
- local old_v = rawget(t, k)
- if not old_v and rawget(t, 'set') then
- t.set(k..' '..v)
- end
- end
- })
-end
-
-- Make sandboxed environment
local function make_sandbox(defined)
local __protected = { worker = true, env = true, modules = true, cache = true, net = true, trust_anchors = true }