... 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.
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);
}
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);
}
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)
/* 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 */
#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 */
+
}
/** 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
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
#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)
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, "_");
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
*/
#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);
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. */
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);
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) { \
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;
}
}
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);
}
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.
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);
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)
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;
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)
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) {
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)
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)
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),
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
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;
}
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
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);
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