module API+ABI: remove one level of indirection

... for layers and props.  This breaks C module API+ABI.

It seemed weird to repeatedly call a function that returns a pointer
to a structure in which we find the function we want to actually call.
We've never used changing these functions AFAIK, and the target
functions could easily be written to change their behavior instead
(i.e. move the indirection *inside* the function).

When breaking this, I also removed these two (_layers and _props)
from the dynamic symbols (to be) exported from the C modules.
They always pointed to memory belonging inside the module,
and they seem quite sensible to be set up by the _init symbol instead.
parent e806b5f9
......@@ -662,13 +662,13 @@ int engine_init(struct engine *engine, knot_mm_t *pool)
return ret;
}
/** Unregister a (found) module */
static void engine_unload(struct engine *engine, struct kr_module *module)
{
/* Unregister module */
auto_free char *name = strdup(module->name);
kr_module_unload(module);
/* Clear in Lua world, but not for embedded modules ('cache' in particular). */
if (name && !kr_module_embedded(name)) {
if (name && !kr_module_get_embedded(name)) {
lua_pushnil(engine->L);
lua_setglobal(engine->L, name);
}
......@@ -821,8 +821,7 @@ static int register_properties(struct engine *engine, struct kr_module *module)
REGISTER_MODULE_CALL(engine->L, module, module->config, "config");
}
const struct kr_prop *p = module->props == NULL ? NULL : module->props();
for (; p && p->name; ++p) {
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);
}
......
......@@ -246,14 +246,6 @@ static kr_layer_api_t *l_ffi_layer_create(lua_State *L, struct kr_module *module
return api;
}
/** @internal Retrieve C layer api wrapper. */
static const kr_layer_api_t *l_ffi_layer(struct kr_module *module)
{
if (module) {
return (const kr_layer_api_t *)module->data;
}
return NULL;
}
#undef LAYER_REGISTER
int ffimodule_register_lua(struct engine *engine, struct kr_module *module, const char *name)
......@@ -278,8 +270,9 @@ int ffimodule_register_lua(struct engine *engine, struct kr_module *module, cons
/* Bake layer API if defined in module */
lua_getfield(L, -1, "layer");
if (!lua_isnil(L, -1)) {
module->layer = &l_ffi_layer;
module->data = l_ffi_layer_create(L, module);
module->layer = l_ffi_layer_create(L, module);
/* 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 */
......
......@@ -18,14 +18,15 @@
#include "lib/cache/api.h"
/** Module implementation. */
const kr_layer_api_t *cache_layer(struct kr_module *module)
int cache_init(struct kr_module *self)
{
static const kr_layer_api_t _layer = {
static const kr_layer_api_t layer = {
.produce = &cache_peek,
.consume = &cache_stash,
};
return &_layer;
self->layer = &layer;
return kr_ok();
}
KR_MODULE_EXPORT(cache)
KR_MODULE_EXPORT(cache) /* useless for builtin module, but let's be consistent */
......@@ -1111,17 +1111,18 @@ static int resolve(kr_layer_t *ctx, knot_pkt_t *pkt)
}
/** Module implementation. */
const kr_layer_api_t *iterate_layer(struct kr_module *module)
int iterate_init(struct kr_module *self)
{
static const kr_layer_api_t _layer = {
static const kr_layer_api_t layer = {
.begin = &begin,
.reset = &reset,
.consume = &resolve,
.produce = &prepare_query
};
return &_layer;
self->layer = &layer;
return kr_ok();
}
KR_MODULE_EXPORT(iterate)
KR_MODULE_EXPORT(iterate) /* useless for builtin module, but let's be consistent */
#undef VERBOSE_MSG
......@@ -1116,21 +1116,17 @@ static int validate(kr_layer_t *ctx, knot_pkt_t *pkt)
VERBOSE_MSG(qry, "<= answer valid, OK\n");
return KR_STATE_DONE;
}
/** Module implementation. */
const kr_layer_api_t *validate_layer(struct kr_module *module)
int validate_init(struct kr_module *self)
{
static const kr_layer_api_t _layer = {
static const kr_layer_api_t layer = {
.consume = &validate,
};
/* Store module reference */
return &_layer;
}
int validate_init(struct kr_module *module)
{
self->layer = &layer;
return kr_ok();
}
KR_MODULE_EXPORT(validate)
KR_MODULE_EXPORT(validate) /* useless for builtin module, but let's be consistent */
#undef VERBOSE_MSG
......@@ -23,16 +23,21 @@
#include "lib/utils.h"
#include "lib/module.h"
/* List of embedded modules */
const kr_layer_api_t *iterate_layer(struct kr_module *module);
const kr_layer_api_t *validate_layer(struct kr_module *module);
const kr_layer_api_t *cache_layer(struct kr_module *module);
static const struct kr_module embedded_modules[] = {
{ "iterate", NULL, NULL, NULL, iterate_layer, NULL, NULL, NULL },
{ "validate", NULL, NULL, NULL, validate_layer, NULL, NULL, NULL },
{ "cache", NULL, NULL, NULL, cache_layer, NULL, NULL, NULL },
};
/* List of embedded modules. These aren't (un)loaded. */
int iterate_init(struct kr_module *self);
int validate_init(struct kr_module *self);
int cache_init(struct kr_module *self);
kr_module_init_cb kr_module_get_embedded(const char *name)
{
if (strcmp(name, "iterate") == 0)
return iterate_init;
if (strcmp(name, "validate") == 0)
return validate_init;
if (strcmp(name, "cache") == 0)
return cache_init;
return NULL;
}
/** Load prefixed symbol. */
static void *load_symbol(void *lib, const char *prefix, const char *name)
......@@ -60,30 +65,16 @@ static int load_library(struct kr_module *module, const char *name, const char *
return kr_error(ENOENT);
}
const struct kr_module * kr_module_embedded(const char *name)
{
for (unsigned i = 0; i < sizeof(embedded_modules)/sizeof(embedded_modules[0]); ++i) {
if (strcmp(name, embedded_modules[i].name) == 0)
return embedded_modules + i;
}
return NULL;
}
/** Load C module symbols. */
static int load_sym_c(struct kr_module *module, uint32_t api_required)
{
module->init = kr_module_get_embedded(module->name);
if (module->init) {
return kr_ok();
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic" /* casts after load_symbol() */
/* Check if it's embedded first */
const struct kr_module *embedded = kr_module_embedded(module->name);
if (embedded) {
module->init = embedded->init;
module->deinit = embedded->deinit;
module->config = embedded->config;
module->layer = embedded->layer;
module->props = embedded->props;
return kr_ok();
}
/* Load dynamic library module */
auto_free char *m_prefix = kr_strcatdup(2, module->name, "_");
......@@ -102,9 +93,14 @@ static int load_sym_c(struct kr_module *module, uint32_t api_required)
ML(init);
ML(deinit);
ML(config);
ML(layer);
ML(props);
#undef ML
if (load_symbol(module->lib, m_prefix, "layer")
|| load_symbol(module->lib, m_prefix, "props")) {
/* In case someone re-compiled against new kresd
* but haven't actually changed the symbols. */
kr_log_error("[system] module %s needs to change API.\n", module->name);
return kr_error(ENOTSUP);
}
return kr_ok();
#pragma GCC diagnostic pop
......
......@@ -35,7 +35,7 @@ struct kr_prop;
*/
#define KR_MODULE_EXPORT(module) \
KR_EXPORT uint32_t module ## _api() { return KR_MODULE_API; }
#define KR_MODULE_API ((uint32_t) 0x20180401)
#define KR_MODULE_API ((uint32_t) 0x20190314)
typedef uint32_t (module_api_cb)(void);
......@@ -55,10 +55,10 @@ struct kr_module {
int (*deinit)(struct kr_module *self);
/** Configure with encoded JSON (NULL if missing). @return error code. */
int (*config)(struct kr_module *self, const char *input);
/** Get a pointer to packet processing API specs. See docs on that type. */
const kr_layer_api_t * (*layer)(struct kr_module *self);
/** Get a pointer to list of properties, terminated by { NULL, NULL, NULL }. */
const struct kr_prop * (*props)(void);
/** Packet processing API specs. May be NULL. See docs on that type. */
const kr_layer_api_t *layer;
/** List of properties. May be NULL. Terminated by { NULL, NULL, NULL }. */
const struct kr_prop *props;
void *lib; /**< Shared library handle or RTLD_DEFAULT */
void *data; /**< Custom data context. */
......@@ -103,9 +103,10 @@ int kr_module_load(struct kr_module *module, const char *name, const char *path)
KR_EXPORT
void kr_module_unload(struct kr_module *module);
typedef int (*kr_module_init_cb)(struct kr_module *);
/**
* Get embedded module prototype by name (or NULL).
* Get embedded module's init function by name (or NULL).
*/
KR_EXPORT
const struct kr_module * kr_module_embedded(const char *name);
kr_module_init_cb kr_module_get_embedded(const char *name);
......@@ -108,7 +108,7 @@ static int answer_finalize_yield(kr_layer_t *ctx) { return kr_ok(); }
for (size_t i = (from); i < (r)->ctx->modules->len; ++i) { \
struct kr_module *mod = (r)->ctx->modules->at[i]; \
if (mod->layer) { \
struct kr_layer layer = {.state = (r)->state, .api = mod->layer(mod), .req = (r)}; \
struct kr_layer layer = {.state = (r)->state, .api = mod->layer, .req = (r)}; \
if (layer.api && layer.api->func) { \
(r)->state = layer.api->func(&layer, ##__VA_ARGS__); \
if ((r)->state == KR_STATE_YIELD) { \
......@@ -127,8 +127,7 @@ static int answer_finalize_yield(kr_layer_t *ctx) { return kr_ok(); }
static inline size_t layer_id(struct kr_request *req, const struct kr_layer_api *api) {
module_array_t *modules = req->ctx->modules;
for (size_t i = 0; i < modules->len; ++i) {
struct kr_module *mod = modules->at[i];
if (mod->layer && mod->layer(mod) == api) {
if (modules->at[i]->layer == api) {
return i;
}
}
......
......@@ -766,7 +766,7 @@ static char *callprop(struct kr_module *module, const char *prop, const char *in
if (!module || !module->props || !prop) {
return NULL;
}
for (const struct kr_prop *p = module->props(); p && p->name; ++p) {
for (const struct kr_prop *p = module->props; p && p->name; ++p) {
if (p->cb != NULL && strcmp(p->name, prop) == 0) {
return p->cb(env, module, input);
}
......
......@@ -16,6 +16,8 @@ Currently modules written in C and LuaJIT are supported.
The anatomy of an extension
===========================
FIXME: review and fix.
A module is a shared object or script defining specific functions, here's an overview.
*Note* |---| the :ref:`Modules <lib_api_modules>` header documents the module loading and API.
......
......@@ -105,6 +105,18 @@ static char* dump_frequent(void *env, struct kr_module *module, const char *args
KR_EXPORT
int bogus_log_init(struct kr_module *module)
{
static kr_layer_api_t layer = {
.consume = &consume,
};
layer.data = module;
module->layer = &layer;
static const struct kr_prop props[] = {
{ &dump_frequent, "frequent", "List most frequent queries.", },
{ NULL, NULL, NULL }
};
module->props = props;
struct stat_data *data = malloc(sizeof(*data));
if (!data) {
return kr_error(ENOMEM);
......@@ -126,25 +138,4 @@ int bogus_log_deinit(struct kr_module *module)
return kr_ok();
}
KR_EXPORT
const kr_layer_api_t *bogus_log_layer(struct kr_module *module)
{
static kr_layer_api_t _layer = {
.consume = &consume,
};
_layer.data = module;
return &_layer;
}
KR_EXPORT
struct kr_prop *bogus_log_props(void)
{
static struct kr_prop prop_list[] = {
{ &dump_frequent, "frequent", "List most frequent queries.", },
{ NULL, NULL, NULL }
};
return prop_list;
}
KR_MODULE_EXPORT(bogus_log)
......@@ -47,6 +47,22 @@ static char *cookies_config(void *env, struct kr_module *module,
KR_EXPORT
int cookies_init(struct kr_module *module)
{
/* The function answer_finalize() in resolver is called before any
* .finish callback. Therefore this layer does not use it. */
static kr_layer_api_t layer = {
.begin = &check_request,
.consume = &check_response
};
/* Store module reference */
layer.data = module;
module->layer = &layer;
static const struct kr_prop props[] = {
{ &cookies_config, "config", "Empty value to return current configuration.", },
{ NULL, NULL, NULL }
};
module->props = props;
struct engine *engine = module->data;
struct kr_cookie_ctx *cookie_ctx = &engine->resolver.cookie_ctx;
......@@ -72,29 +88,4 @@ int cookies_deinit(struct kr_module *module)
return kr_ok();
}
KR_EXPORT
const kr_layer_api_t *cookies_layer(struct kr_module *module)
{
/* The function answer_finalize() in resolver is called before any
* .finish callback. Therefore this layer does not use it. */
static kr_layer_api_t _layer = {
.begin = &check_request,
.consume = &check_response
};
/* Store module reference */
_layer.data = module;
return &_layer;
}
KR_EXPORT
struct kr_prop *cookies_props(void)
{
static struct kr_prop prop_list[] = {
{ &cookies_config, "config", "Empty value to return current configuration.", },
{ NULL, NULL, NULL }
};
return prop_list;
}
KR_MODULE_EXPORT(cookies)
......@@ -211,6 +211,13 @@ static int dnstap_log(kr_layer_t *ctx) {
KR_EXPORT
int dnstap_init(struct kr_module *module) {
static kr_layer_api_t layer = {
.finish = &dnstap_log,
};
/* Store module reference */
layer.data = module;
module->layer = &layer;
/* allocated memory for internal data */
struct dnstap_data *data = malloc(sizeof(*data));
if (!data) {
......@@ -368,15 +375,5 @@ int dnstap_config(struct kr_module *module, const char *conf) {
return kr_ok();
}
KR_EXPORT
const kr_layer_api_t *dnstap_layer(struct kr_module *module) {
static kr_layer_api_t _layer = {
.finish = &dnstap_log,
};
/* Store module reference */
_layer.data = module;
return &_layer;
}
KR_MODULE_EXPORT(dnstap)
......@@ -62,15 +62,13 @@ static int edns_keepalive_finalize(kr_layer_t *ctx)
return ctx->state;
}
KR_EXPORT
const kr_layer_api_t *edns_keepalive_layer(struct kr_module *module)
KR_EXPORT int edns_keeapalive_init(struct kr_module *self)
{
static kr_layer_api_t _layer = {
static const kr_layer_api_t layer = {
.answer_finalize = &edns_keepalive_finalize,
};
/* Store module reference */
_layer.data = module;
return &_layer;
self->layer = &layer;
return kr_ok();
}
KR_MODULE_EXPORT(edns_keepalive)
......
......@@ -600,26 +600,30 @@ static char* hint_ttl(void *env, struct kr_module *module, const char *args)
return result;
}
/*
* Module implementation.
*/
/** Basic initialization: get a memory pool, etc. */
KR_EXPORT
const kr_layer_api_t *hints_layer(struct kr_module *module)
int hints_init(struct kr_module *module)
{
static kr_layer_api_t _layer = {
static kr_layer_api_t layer = {
.produce = &query,
};
/* Store module reference */
_layer.data = module;
return &_layer;
}
layer.data = module;
module->layer = &layer;
static const struct kr_prop props[] = {
{ &hint_set, "set", "Set {name, address} hint.", },
{ &hint_del, "del", "Delete one {name, address} hint or all addresses for the name.", },
{ &hint_get, "get", "Retrieve hint for given name.", },
{ &hint_ttl, "ttl", "Set/get TTL used for the hints.", },
{ &hint_add_hosts, "add_hosts", "Load a file with hosts-like formatting and add contents into hints.", },
{ &hint_root, "root", "Replace root hints set (empty value to return current list).", },
{ &hint_root_file, "root_file", "Replace root hints set from a zonefile.", },
{ &hint_use_nodata, "use_nodata", "Synthesise NODATA if name matches, but type doesn't. True by default.", },
{ NULL, NULL, NULL }
};
module->props = props;
/** Basic initialization: get a memory pool, etc. */
KR_EXPORT
int hints_init(struct kr_module *module)
{
/* Create pool and copy itself */
knot_mm_t _pool = {
.ctx = mp_new(4096),
......@@ -678,23 +682,6 @@ int hints_config(struct kr_module *module, const char *conf)
return kr_ok();
}
KR_EXPORT
struct kr_prop *hints_props(void)
{
static struct kr_prop prop_list[] = {
{ &hint_set, "set", "Set {name, address} hint.", },
{ &hint_del, "del", "Delete one {name, address} hint or all addresses for the name.", },
{ &hint_get, "get", "Retrieve hint for given name.", },
{ &hint_ttl, "ttl", "Set/get TTL used for the hints.", },
{ &hint_add_hosts, "add_hosts", "Load a file with hosts-like formatting and add contents into hints.", },
{ &hint_root, "root", "Replace root hints set (empty value to return current list).", },
{ &hint_root_file, "root_file", "Replace root hints set from a zonefile.", },
{ &hint_use_nodata, "use_nodata", "Synthesise NODATA if name matches, but type doesn't. True by default.", },
{ NULL, NULL, NULL }
};
return prop_list;
}
KR_MODULE_EXPORT(hints)
#undef VERBOSE_MSG
......@@ -57,26 +57,6 @@ static int nsid_finalize(kr_layer_t *ctx) {
return ctx->state;
}
KR_EXPORT
const kr_layer_api_t *nsid_layer(struct kr_module *module)
{
static kr_layer_api_t _layer = {
.answer_finalize = &nsid_finalize,
};
_layer.data = module;
return &_layer;
}
KR_EXPORT
int nsid_init(struct kr_module *module) {
struct nsid_config *config = calloc(1, sizeof(struct nsid_config));
if (config == NULL)
return kr_error(ENOMEM);
module->data = config;
return kr_ok();
}
static char* nsid_name(void *env, struct kr_module *module, const char *args)
{
struct engine *engine = env;
......@@ -99,13 +79,25 @@ static char* nsid_name(void *env, struct kr_module *module, const char *args)
}
KR_EXPORT
struct kr_prop *nsid_props(void)
{
static struct kr_prop prop_list[] = {
int nsid_init(struct kr_module *module) {
static kr_layer_api_t layer = {
.answer_finalize = &nsid_finalize,
};
layer.data = module;
module->layer = &layer;
static const struct kr_prop props[] = {
{ &nsid_name, "name", "Get or set local NSID value" },
{ NULL, NULL, NULL }
};
return prop_list;
module->props = props;
struct nsid_config *config = calloc(1, sizeof(struct nsid_config));
if (config == NULL)
return kr_error(ENOMEM);
module->data = config;
return kr_ok();
}
KR_EXPORT
......
......@@ -460,26 +460,29 @@ static char* dump_upstreams(void *env, struct kr_module *module, const char *arg
return ret;
}
/*
* Module implementation.
*/
KR_EXPORT
const kr_layer_api_t *stats_layer(struct kr_module *module)
int stats_init(struct kr_module *module)
{
static kr_layer_api_t _layer = {
static kr_layer_api_t layer = {
.consume = &collect_rtt,
.finish = &collect,
.begin = &collect_transport,
};
/* Store module reference */
_layer.data = module;
return &_layer;
}
layer.data = module;
module->layer = &layer;
static const struct kr_prop props[] = {
{ &stats_set, "set", "Set {key, val} metrics.", },
{ &stats_get, "get", "Get metrics for given key.", },
{ &stats_list, "list", "List observed metrics.", },
{ &dump_frequent, "frequent", "List most frequent queries.", },
{ &clear_frequent,"clear_frequent", "Clear frequent queries log.", },
{ &dump_upstreams, "upstreams", "List recently seen authoritatives.", },
{ NULL, NULL, NULL }
};
module->props = props;
KR_EXPORT
int stats_init(struct kr_module *module)
{
struct stat_data *data = malloc(sizeof(*data));
if (!data) {
return kr_error(ENOMEM);
......@@ -513,21 +516,6 @@ int stats_deinit(struct kr_module *module)
return kr_ok();
}
KR_EXPORT
struct kr_prop *stats_props(void)
{
static struct kr_prop prop_list[] = {
{ &stats_set, "set", "Set {key, val} metrics.", },
{ &stats_get, "get", "Get metrics for given key.", },
{ &stats_list, "list", "List observed metrics.", },
{ &dump_frequent, "frequent", "List most frequent queries.", },
{ &clear_frequent,"clear_frequent", "Clear frequent queries log.", },
{ &dump_upstreams, "upstreams", "List recently seen authoritatives.", },
{ NULL, NULL, NULL }
};
return prop_list;
}
KR_MODULE_EXPORT(stats)
#undef VERBOSE_MSG
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment