]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
lib: loadable versioned modules (api subject to change)
authorMarek Vavruša <marek.vavrusa@nic.cz>
Mon, 23 Feb 2015 09:13:29 +0000 (10:13 +0100)
committerMarek Vavruša <marek.vavrusa@nic.cz>
Mon, 23 Feb 2015 09:13:29 +0000 (10:13 +0100)
27 files changed:
Makefile
config.mk
daemon/worker.c
help.mk
lib/context.c
lib/context.h
lib/defines.h
lib/layer/iterate.c
lib/layer/iterate.h
lib/layer/itercache.c
lib/layer/itercache.h
lib/layer/stats.c [deleted file]
lib/libkresolve.mk
lib/module.c [new file with mode: 0644]
lib/module.h [new file with mode: 0644]
lib/resolve.c
lib/utils.c [new file with mode: 0644]
lib/utils.h [moved from lib/layer/static.h with 66% similarity]
modules/gostats/gostats.go [new file with mode: 0644]
modules/gostats/gostats.mk [new file with mode: 0644]
modules/hints/hints.c [moved from lib/layer/static.c with 62% similarity]
modules/hints/hints.mk [new file with mode: 0644]
modules/modules.mk [new file with mode: 0644]
platform.mk
tests/test_integration.c
tests/test_utils.c [moved from lib/layer/stats.h with 50% similarity]
tests/tests.mk

index ad004827a73a80861706aca4498c2986d8eeda7a..961724b817964925b88307c76db4ea0d252a0475 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,10 +2,10 @@ include config.mk
 include platform.mk
 
 # Targets
-all: info libkresolve kresolved
-install: libkresolve-install kresolved-install
+all: info libkresolve modules kresolved
+install: libkresolve-install modules-install kresolved-install
 check: all tests-check
-clean: libkresolve-clean kresolved-clean tests-clean
+clean: libkresolve-clean modules-clean kresolved-clean tests-clean
 .PHONY: all install check clean
 
 # Options
@@ -25,4 +25,5 @@ CFLAGS += $(libknot_CFLAGS) $(libuv_CFLAGS) $(cmocka_CFLAGS) $(python_CFLAGS)
 include help.mk
 include lib/libkresolve.mk
 include daemon/kresolved.mk
+include modules/modules.mk
 include tests/tests.mk
index 6a302c22d2384b8a0dc0cc5f3abb8e0f64bcbdf5..e2c7839ac1fc829d58ee2a6df4cfccefc0620ad2 100644 (file)
--- a/config.mk
+++ b/config.mk
@@ -6,13 +6,15 @@ MINOR := 04
 PREFIX := /usr/local
 BINDIR := /bin
 LIBDIR := /lib
-INCLUDEDIR = /include
+INCLUDEDIR := /include
+MODULEDIR := $(LIBDIR)/kdns_modules
 
 # Tools
 ifndef CC
 CC     := cc
 endif
-CFLAGS += -std=c99 -D_GNU_SOURCE -Wall -fPIC -I$(abspath .) -DPACKAGE_VERSION="\"$(MAJOR).$(MINOR)\""
+CFLAGS += -std=c99 -D_GNU_SOURCE -Wall -fPIC -I$(abspath .)
+CFLAGS  += -DPACKAGE_VERSION="\"$(MAJOR).$(MINOR)\"" -DPREFIX="\"$(PREFIX)\"" -DMODULEDIR="\"$(MODULEDIR)\""
 RM     := rm -f
 LN  := ln -s
 INSTALL := install
index 4d0e351b889c26dc5012a9a2346abc2418726b66..9dce753e042bd1eb3702ff3a8a541b1726573b87 100644 (file)
@@ -44,11 +44,16 @@ int worker_init(struct worker_ctx *worker, mm_ctx_t *mm)
        /* Open resolution context cache */
        worker->resolve.cache = kr_cache_open("/tmp/kresolved", mm, CACHE_DEFAULT_SIZE);
        if (worker->resolve.cache == NULL) {
-               fprintf(stderr, "Cache directory '/tmp/kresolved' not exists, exitting.\n");
+               fprintf(stderr, "Cache directory '/tmp/kresolved' not exists, exiting.\n");
                kr_context_deinit(&worker->resolve);
                return KNOT_ERROR;
        }
 
+       /* Load basic modules */
+       kr_context_register(&worker->resolve, "iterate");
+       kr_context_register(&worker->resolve, "itercache");
+       kr_context_register(&worker->resolve, "hints");
+
        return KNOT_EOK;
 }
 
diff --git a/help.mk b/help.mk
index 34c89aaaf24765d43879148f996d589fef394866..63d0408bce28700b5be3127547879cb2954a60f8 100644 (file)
--- a/help.mk
+++ b/help.mk
@@ -7,6 +7,7 @@ info:
        $(info BINDIR:     $(BINDIR))
        $(info LIBDIR:     $(LIBDIR))
        $(info INCLUDEDIR: $(INCLUDEDIR))
+       $(info MODULEDIR:  $(MODULEDIR))
        $(info )
        $(info Features)
        $(info --------)
index 9de4c3d65e42bd91faa3fe778f12f44f02b90965..16789a87f19119a457c1cea163e889ce19287f5b 100644 (file)
  */
 
 #include <string.h>
+#include <limits.h>
 
 #include <libknot/errcode.h>
 #include <libknot/internal/sockaddr.h>
+#include <libknot/internal/mem.h>
+
 #include "lib/context.h"
+#include "lib/defines.h"
 #include "lib/rplan.h"
 
 int kr_context_init(struct kr_context *ctx, mm_ctx_t *mm)
@@ -43,5 +47,28 @@ int kr_context_deinit(struct kr_context *ctx)
                kr_cache_close(ctx->cache);
        }
 
+       for (size_t i = 0; i < ctx->mod_loaded; ++i) {
+               kr_module_unload(&ctx->modules[i]);
+       }
+
        return KNOT_EOK;
 }
+
+int kr_context_register(struct kr_context *ctx, const char *module_name)
+{
+       size_t last = ctx->mod_loaded;
+       int ret = mreserve((char **) &ctx->modules, sizeof(struct kr_module),
+                          last + 1, 0, &ctx->mod_reserved);
+       if (ret < 0) {
+               return kr_error(ENOMEM);
+       }
+
+       struct kr_module *mod = &ctx->modules[last];
+       ret = kr_module_load(mod, module_name, NULL);
+       if (ret != 0) {
+               return ret;
+       }
+
+       ctx->mod_loaded += 1;
+       return kr_ok();
+}
index 5d68f5ff489facfb40b25b14b523d86d923673f8..08d9209b67918bd8b449e7d43a2e00477a5b7846 100644 (file)
@@ -19,6 +19,7 @@
 #include <libknot/internal/mempattern.h>
 #include <libknot/internal/lists.h>
 
+#include "lib/module.h"
 #include "lib/cache.h"
 
 /*!
  */
 struct kr_context
 {
-       struct kr_cache *cache;
-       list_t layers;
-       unsigned options;
-       mm_ctx_t *pool;
+    mm_ctx_t *pool;
+    struct kr_cache *cache;
+    struct kr_module *modules;
+    size_t mod_loaded;
+    size_t mod_reserved;
+    uint32_t options;
 };
 
 /*!
@@ -51,3 +54,11 @@ int kr_context_init(struct kr_context *ctx, mm_ctx_t *mm);
  * \return KNOT_E*
  */
 int kr_context_deinit(struct kr_context *ctx);
+
+/*!
+ * \brief Register module to context.
+ * \param ctx context
+ * \param module_name
+ * \return KNOT_E*
+ */
+int kr_context_register(struct kr_context *ctx, const char *module_name);
index e0cf92d80e347b59ab130237d2f40cadab40efad..f1db0202bb7cc7519f54aae1f57bf49f10019d3b 100644 (file)
 
 #pragma once
 
+#include <errno.h>
 #include <libknot/errcode.h>
 #include <libknot/dname.h>
 #include <libknot/rrset.h>
 
+/*
+ * Error codes.
+ */
+#define kr_ok() 0
+#define kr_error(x) -abs(x)
+#define kr_strerror(x) strerror(abs(x))
+
 /*
  * Connection limits.
  */
@@ -36,4 +44,4 @@
 #define KR_DNS_PORT   53
 #define KR_DNAME_ROOT ((const knot_dname_t*)"")
 #define KR_EDNS_VERSION 0
-#define KR_EDNS_PAYLOAD 4096
+#define KR_EDNS_PAYLOAD 4096
\ No newline at end of file
index a0ac5b851e5cc141cd973e1a9dff893c1193c905..c16c7b68c7c45e3c757138865e548f35efe4cf6b 100644 (file)
@@ -26,6 +26,7 @@
 #include "lib/rplan.h"
 #include "lib/defines.h"
 #include "lib/nsrep.h"
+#include "lib/module.h"
 
 #define DEBUG_MSG(fmt...) QRDEBUG(kr_rplan_current(param->rplan), "iter", fmt)
 
@@ -463,16 +464,14 @@ static int resolve(knot_layer_t *ctx, knot_pkt_t *pkt)
 }
 
 /*! \brief Module implementation. */
-static const knot_layer_api_t LAYER_ITERATE_MODULE = {
-       &begin,
-       &reset,
-       &finish,
-       &resolve,
-       &prepare_query,
-       NULL
-};
-
-const knot_layer_api_t *layer_iterate_module(void)
+const knot_layer_api_t *iterate_layer(void)
 {
-       return &LAYER_ITERATE_MODULE;
-}
+       static const knot_layer_api_t _layer = {
+               .begin = &begin,
+               .reset = &reset,
+               .finish = &finish,
+               .in = &resolve,
+               .out = &prepare_query
+       };
+       return &_layer;
+}
\ No newline at end of file
index a5821ac9bc7bd51f88a7d7fbe450d58019e0cdd4..758f7d39ea3c7403f866fcfac26405c6de85be1c 100644 (file)
@@ -19,8 +19,7 @@
 #include "lib/layer.h"
 
 /* Processing module implementation. */
-const knot_layer_api_t *layer_iterate_module(void);
-#define LAYER_ITERATE layer_iterate_module()
+extern const knot_layer_api_t *iterate_layer(void);
 
 /*!
  * \brief Result updates the query parent.
index 0b0e501fe49c71a9a3f3e640989b8e98be3f5ab6..bbc709e51dd730f8bbacbade75952986159f7d58 100644 (file)
@@ -20,8 +20,8 @@
 #include <libknot/internal/mempool.h>
 #include <libknot/rrtype/rdname.h>
 
-#include "lib/layer/static.h"
 #include "lib/layer/iterate.h"
+#include "lib/module.h"
 
 #define DEBUG_MSG(fmt...) QRDEBUG(kr_rplan_current(param->rplan), " cc ",  fmt)
 
@@ -267,16 +267,13 @@ static int write_cache(knot_layer_t *ctx, knot_pkt_t *pkt)
 }
 
 /*! \brief Module implementation. */
-static const knot_layer_api_t LAYER_ITERCACHE_MODULE = {
-        &begin,
-        NULL,
-        NULL,
-        &write_cache,
-        &read_cache,
-        NULL
-};
-
-const knot_layer_api_t *layer_itercache_module(void)
+const knot_layer_api_t *itercache_layer(void)
 {
-       return &LAYER_ITERCACHE_MODULE;
+       static const knot_layer_api_t _layer = {
+               .begin = &begin,
+               .in = &write_cache,
+               .out = &read_cache
+       };
+
+       return &_layer;
 }
index 5f3b7c2e147cea792c460c0be3fc7c443b63f868..532196b0852b47238d99404b5d16fcce6676c1c3 100644 (file)
@@ -19,5 +19,4 @@
 #include "lib/layer.h"
 
 /* Processing module implementation. */
-const knot_layer_api_t *layer_itercache_module(void);
-#define LAYER_ITERCACHE layer_itercache_module()
+extern const knot_layer_api_t *itercache_layer(void);
diff --git a/lib/layer/stats.c b/lib/layer/stats.c
deleted file mode 100644 (file)
index 610f84c..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/*  Copyright (C) 2014 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
-
-    This program is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <libknot/internal/print.h>
-
-#include "lib/layer/stats.h"
-#include "lib/rplan.h"
-
-#define DEBUG_MSG(fmt...) QRDEBUG(NULL, "stat",  fmt)
-
-//static void update_stats(struct kr_ns *ns, double rtt)
-//{
-//     /* Knuth, TAOCP, p.232 (Welford running variance/mean). */
-//     double d_mean = (rtt - ns->stat.M);
-//     ns->stat.n += 1;
-//     ns->stat.M += d_mean / ns->stat.n;
-//     ns->stat.S += d_mean * (rtt - ns->stat.M);
-//}
-
-static int begin(knot_layer_t *ctx, void *param)
-{
-       ctx->data = param;
-       return ctx->state;
-}
-
-static int finish(knot_layer_t *ctx)
-{
-#ifndef NDEBUG
-       struct kr_layer_param *param = ctx->data;
-       struct kr_rplan *rplan = param->rplan;
-       const knot_pkt_t *answer = param->answer;
-
-       /* Calculate total RTT and number of queries. */
-       double total_rtt = 0.0;
-       size_t nr_queries = list_size(&rplan->resolved);
-       if (nr_queries > 0) {
-               struct kr_query *query_first = HEAD(rplan->resolved);
-               struct timeval t_end;
-               gettimeofday(&t_end, NULL);
-               total_rtt = time_diff(&query_first->timestamp, &t_end);
-       }
-
-       lookup_table_t *rcode = lookup_by_id(knot_rcode_names, knot_wire_get_rcode(answer->wire));
-       DEBUG_MSG("result => %s [%u records]\n", rcode ? rcode->name : "??", answer->rrset_count);
-       DEBUG_MSG("rtt => %.02lf [ms]\n",  total_rtt);
-#endif
-
-       return ctx->state;
-}
-
-/*! \brief Module implementation. */
-static const knot_layer_api_t LAYER_STATS_MODULE = {
-       &begin,
-       NULL,
-       &finish,
-       NULL,
-       NULL,
-       NULL
-};
-
-const knot_layer_api_t *layer_stats_module(void)
-{
-       return &LAYER_STATS_MODULE;
-}
index 9dddbb69b519d0332592a141d0c5075795a8de58..4955b2589fcd75a2f6aed1e7fa3b2d6866380f02 100644 (file)
@@ -1,9 +1,9 @@
 libkresolve_SOURCES := \
        lib/layer/iterate.c    \
        lib/layer/itercache.c  \
-       lib/layer/static.c     \
-       lib/layer/stats.c      \
+       lib/utils.c            \
        lib/nsrep.c            \
+       lib/module.c           \
        lib/context.c          \
        lib/resolve.c          \
        lib/zonecut.c          \
@@ -11,12 +11,10 @@ libkresolve_SOURCES := \
        lib/cache.c
 
 libkresolve_HEADERS := \
-       lib/layer/iterate.h    \
-       lib/layer/itercache.h  \
-       lib/layer/static.h     \
-       lib/layer/stats.h      \
        lib/layer.h            \
+       lib/utils.h            \
        lib/nsrep.h            \
+       lib/module.h           \
        lib/context.h          \
        lib/resolve.h          \
        lib/zonecut.h          \
diff --git a/lib/module.c b/lib/module.c
new file mode 100644 (file)
index 0000000..d87ac0c
--- /dev/null
@@ -0,0 +1,88 @@
+#include <dlfcn.h>
+
+#include "lib/defines.h"
+#include "lib/utils.h"
+#include "lib/module.h"
+
+/*! \brief Library extension. */
+static inline const char *library_ext(void)
+{
+#if defined(__APPLE__)
+       return ".dylib";
+#elif _WIN32
+       return ".lib";
+#else
+       return ".so";
+#endif 
+}
+
+static void *load_symbol(void *lib, const char *prefix, const char *name)
+{
+       auto_free char *symbol = kr_strcatdup(3, prefix, "_", name);
+       return dlsym(lib, symbol);
+}
+
+static int load_library(struct kr_module *module, const char *name, const char *path)
+{
+       if (path == NULL) {
+               return kr_error(EINVAL);
+       }
+
+       auto_free char *lib_path = kr_strcatdup(4, path, "/", name, library_ext());
+       if (lib_path == NULL) {
+               return kr_error(ENOMEM);
+       }
+
+       module->lib = dlopen(lib_path, RTLD_LAZY);
+       if (module->lib) {
+               return kr_ok();
+       }
+
+       return kr_error(ENOENT);
+}
+
+int kr_module_load(struct kr_module *module, const char *name, const char *path)
+{
+       if (load_library(module, name, path) != 0) {
+               if (load_library(module, name, "~/.local/" MODULEDIR) != 0) {
+                       if (load_library(module, name, PREFIX MODULEDIR) != 0) {        
+                       }
+               }
+       }
+
+       /* It's okay if it fails, then current exec space is searched. */
+       if (module->lib == NULL) {
+               module->lib = RTLD_DEFAULT;
+       }
+
+       /* Load all symbols. */
+       module_api_cb *module_api = NULL;
+       *(void **) (&module_api)     = load_symbol(module->lib, name, "api");
+       *(void **) (&module->init)   = load_symbol(module->lib, name, "init");
+       *(void **) (&module->deinit) = load_symbol(module->lib, name, "deinit");
+       *(void **) (&module->config) = load_symbol(module->lib, name, "config");
+       *(void **) (&module->layer)  = load_symbol(module->lib, name, "layer");
+
+       /* Check module API version (if declared). */
+       if (module_api && module_api() > KR_MODULE_API) {
+               return kr_error(ENOTSUP);
+       }
+
+       /* Initialize module */
+       if (module->init) {
+               return module->init(module);
+       }
+
+       return kr_ok();
+}
+
+void kr_module_unload(struct kr_module *module)
+{
+       if (module->deinit) {
+               module->deinit(module);
+       }
+
+       if (module->lib && module->lib != RTLD_DEFAULT) {
+               dlclose(module->lib);
+       }
+}
\ No newline at end of file
diff --git a/lib/module.h b/lib/module.h
new file mode 100644 (file)
index 0000000..6a65d8f
--- /dev/null
@@ -0,0 +1,63 @@
+/*  Copyright (C) 2015 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <libknot/processing/layer.h>
+
+/*
+ * Forward decls
+ */
+struct kr_module;
+
+/*
+ * API definition.
+ */
+#define KR_MODULE_API 0x20150401 /*!< API version */
+typedef uint32_t (module_api_cb)(void);
+typedef int (module_init_cb)(struct kr_module *);
+typedef int (module_deinit_cb)(struct kr_module *);
+typedef int (module_config_cb)(struct kr_module *, void *);
+typedef const knot_layer_api_t* (module_layer_cb)(void);
+
+/*! Loaded module representation. */ 
+struct kr_module {
+    module_init_cb   *init;   /*!< Constructor */
+    module_deinit_cb *deinit; /*!< Destructor */
+    module_config_cb *config; /*!< Configuration */
+    module_layer_cb  *layer;  /*!< Layer getter */
+    void *lib;                /*!< Shared library handle or RTLD_DEFAULT */
+    void *data;               /*!< Custom data context. */
+};
+
+/*! Load module instance into memory.
+ * @param module module structure
+ * @param name module name
+ * @param path module search path
+ * @return 0 or an error
+ */
+int kr_module_load(struct kr_module *module, const char *name,  const char *path);
+
+/*! Unload module instance.
+ * @param module module structure
+ */
+void kr_module_unload(struct kr_module *module);
+
+/*! Export module API version (place this at the end of your module).
+ * @param module module name (f.e. hints)
+ */
+#define KR_MODULE_EXPORT(module) \
+    uint32_t module ## _api() { return KR_MODULE_API; }
\ No newline at end of file
index 495ead18555e656911919ee5fd154d1931eb388f..fdbab518e0702c716eeef7e9fbd72684f8eb6e8e 100755 (executable)
@@ -26,8 +26,6 @@
 #include "lib/defines.h"
 #include "lib/layer/itercache.h"
 #include "lib/layer/iterate.h"
-#include "lib/layer/static.h"
-#include "lib/layer/stats.h"
 
 #define DEBUG_MSG(fmt...) QRDEBUG(kr_rplan_current(param->rplan), "resl",  fmt)
 
@@ -147,15 +145,23 @@ static int iterate(struct knot_requestor *requestor, struct kr_layer_param *para
        return ret;
 }
 
+static void prepare_layers(struct knot_requestor *req, struct kr_layer_param *param)
+{
+       struct kr_context *ctx = param->ctx;
+       for (size_t i = 0; i < ctx->mod_loaded; ++i) {
+               struct kr_module *mod = &ctx->modules[i];
+               if (mod->layer) {
+                       knot_requestor_overlay(req, mod->layer(), param);
+               }
+       }
+}
+
 static int resolve_iterative(struct kr_layer_param *param, mm_ctx_t *pool)
 {
-       /* Initialize requestor and overlay. */
+       /* Initialize requestor. */
        struct knot_requestor requestor;
        knot_requestor_init(&requestor, pool);
-       knot_requestor_overlay(&requestor, LAYER_STATIC, param);
-       knot_requestor_overlay(&requestor, LAYER_ITERCACHE, param);
-       knot_requestor_overlay(&requestor, LAYER_ITERATE, param);
-       knot_requestor_overlay(&requestor, LAYER_STATS, param);
+       prepare_layers(&requestor, param);
 
        /* Iteratively solve the query. */
        int ret = KNOT_EOK;
diff --git a/lib/utils.c b/lib/utils.c
new file mode 100644 (file)
index 0000000..2d0390e
--- /dev/null
@@ -0,0 +1,58 @@
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "lib/defines.h"
+#include "lib/utils.h"
+
+/*
+ * Macros.
+ */
+#define strlen_safe(x) ((x) ? strlen(x) : 0)
+
+/*
+ * Cleanup callbacks.
+ */
+void _cleanup_free(char **p)
+{
+    free(*p);
+}
+
+void _cleanup_close(int *p)
+{
+    if (*p > 0) close(*p);
+}
+
+char* kr_strcatdup(unsigned n, ...)
+{
+    /* Calculate total length */
+    size_t total_len = 0;
+    va_list vl;
+    va_start(vl, n);
+    for (unsigned i = 0; i < n; ++i) {
+        char *item = va_arg(vl, char *);
+        total_len += strlen_safe(item);
+    }
+    va_end(vl);
+
+    /* Allocate result and fill */
+    char *result = NULL;
+    if (total_len > 0) {
+        result = malloc(total_len + 1);
+    }
+    if (result) {
+        char *stream = result;
+        va_start(vl, n);
+        for (unsigned i = 0; i < n; ++i) {
+            char *item = va_arg(vl, char *);
+            if (item) {
+                size_t len = strlen(item);
+                memcpy(stream, item, len + 1);
+                stream += len;
+            }
+        }
+        va_end(vl);
+    }
+
+    return result;
+}
\ No newline at end of file
similarity index 66%
rename from lib/layer/static.h
rename to lib/utils.h
index 8733952eda725404712e6519b3162145094da95f..3d6a57cc51cd4a011a3edcb9fbd677aea42fe215 100644 (file)
 
 #pragma once
 
-#include "lib/layer.h"
+/*
+ * General-purpose attributes.
+ */
+#define auto_free __attribute__((cleanup(_cleanup_free)))
+extern void _cleanup_free(char **p);
+#define auto_close __attribute__((cleanup(_cleanup_close)))
+extern void _cleanup_close(int *p);
+
+/*
+ * Defines.
+ */
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof(*(x)))
 
-/* Processing module implementation. */
-const knot_layer_api_t *layer_static_module(void);
-#define LAYER_STATIC layer_static_module()
+/*! \brief Concatenate N strings. */
+char* kr_strcatdup(unsigned n, ...);
diff --git a/modules/gostats/gostats.go b/modules/gostats/gostats.go
new file mode 100644 (file)
index 0000000..a64b7c0
--- /dev/null
@@ -0,0 +1,36 @@
+package gostats
+
+/*
+#include "lib/layer.h"
+#include "lib/module.h"
+extern int gostats_begin(knot_layer_t *, void *);
+extern int gostats_finish(knot_layer_t *);
+static inline const knot_layer_api_t *_layer(void)
+{
+       static const knot_layer_api_t _module = {
+               .begin = &gostats_begin,
+               .finish = &gostats_finish
+       };
+       return &_module;
+}
+*/
+import "C"
+import "unsafe"
+import "fmt"
+
+//export gostats_begin
+func gostats_begin(ctx *C.knot_layer_t, param unsafe.Pointer) C.int {
+       fmt.Println("go_begin()")
+       return 0
+}
+
+//export gostats_finish
+func gostats_finish(ctx *C.knot_layer_t) C.int {
+       fmt.Println("go_finish()")
+       return 0
+}
+
+//export gostats_layer
+func gostats_layer() *C.knot_layer_api_t {
+       return C._layer()
+}
\ No newline at end of file
diff --git a/modules/gostats/gostats.mk b/modules/gostats/gostats.mk
new file mode 100644 (file)
index 0000000..49a4fb8
--- /dev/null
@@ -0,0 +1,4 @@
+hints_SOURCES := modules/gostats/gostats.g
+gostats_DEPEND := libkresolve
+gostats_LIBS := $(libkresolve_TARGET) $(libkresolve_LIBS)
+$(call make_go_module,gostats)
\ No newline at end of file
similarity index 62%
rename from lib/layer/static.c
rename to modules/hints/hints.c
index d8fa56db81a031143a21454184357254ec883d00..d439015bd8227674b751b0d7ed86aa4d75f5f76c 100644 (file)
     along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "lib/layer/static.h"
+#include "lib/module.h"
+#include "lib/layer.h"
 
 #define DEBUG_MSG(fmt...) QRDEBUG(NULL, "hint",  fmt)
 
-static int reset(knot_layer_t *ctx)
+static int begin(knot_layer_t *ctx, void *module_param)
 {
-       /* TODO: sync, cleanup after resolution */
+       ctx->data = module_param;
        return ctx->state;
 }
 
-static int begin(knot_layer_t *ctx, void *param)
+static int query(knot_layer_t *ctx, knot_pkt_t *pkt)
 {
-       ctx->data = param;
+       return ctx->state;
+}
 
-       /* TODO: read static hosts file */
+/*
+ * Module implementation.
+ */
 
-       return ctx->state;
+const knot_layer_api_t *hints_layer(void)
+{
+       static const knot_layer_api_t _layer = {
+               .begin = &begin,
+               .out = &query
+       };
+       return &_layer;
 }
 
-/*! \brief Module implementation. */
-static const knot_layer_api_t LAYER_STATIC_MODULE = {
-       &begin,
-       &reset,
-       NULL,
-       NULL,
-       NULL,
-       NULL
-};
-
-const knot_layer_api_t *layer_static_module(void)
+int hints_init(struct kr_module *module)
 {
-       return &LAYER_STATIC_MODULE;
+       return 0;
 }
+
+int hints_deinit(struct kr_module *module)
+{
+       return 0;
+}
+
+KR_MODULE_EXPORT(hints);
diff --git a/modules/hints/hints.mk b/modules/hints/hints.mk
new file mode 100644 (file)
index 0000000..2784d04
--- /dev/null
@@ -0,0 +1,4 @@
+hints_SOURCES := modules/hints/hints.c
+hints_DEPEND := libkresolve
+hints_LIBS := $(libkresolve_TARGET) $(libkresolve_LIBS)
+$(call make_c_module,hints)
\ No newline at end of file
diff --git a/modules/modules.mk b/modules/modules.mk
new file mode 100644 (file)
index 0000000..fca344e
--- /dev/null
@@ -0,0 +1,19 @@
+# List of built-in modules
+modules_TARGETS := hints
+
+# Make C module
+define make_c_module
+$(eval $(call make_module,$(1),modules/$(1)))
+endef
+
+# Make Go module
+define make_go_module
+# TODO: compilable only with gccgo -shared
+# go tool cgo -- $(CFLAGS) $$($(1)_SOURCES)
+endef
+
+# Build rules
+modules: $(modules_TARGETS)
+modules-clean: $(addsuffix -clean,$(modules_TARGETS))
+modules-install: $(addsuffix -install,$(modules_TARGETS))
+$(foreach module,$(modules_TARGETS),$(eval include modules/$(module)/$(module).mk))
\ No newline at end of file
index baa535cc843c2967924a9931a8c3832161dc65ef..97b97f027c83d39999c362572c95a33aa6bc133a 100644 (file)
@@ -50,7 +50,8 @@ $(2)/$(1)$(3): $$($(1)_OBJ) $$($(1)_DEPEND)
 $(1)-clean:
        $(RM) $$($(1)_OBJ) $$($(1)_DEP) $(2)/$(1)$(3)
 $(1)-install: $(2)/$(1)$(3)
-       $(INSTALL) $$^ $(PREFIX)/$(5) 
+       $(INSTALL) -d $(PREFIX)/$(5)
+       $(INSTALL) $$^ $(PREFIX)/$(5)
 ifneq ($$(strip $$($(1)_HEADERS)),)
        $(INSTALL) -d $(PREFIX)/$(INCLUDEDIR)/$(1)
        $(INSTALL) $$($(1)_HEADERS) $(PREFIX)/$(INCLUDEDIR)/$(1)
@@ -61,7 +62,8 @@ endef
 # Make targets (name,path)
 make_bin = $(call make_target,$(1),$(2),$(BINEXT),,$(BINDIR))
 make_lib = $(call make_target,$(1),$(2),$(LIBEXT),-$(LIBTYPE),$(LIBDIR))
-make_module = $(call make_target,$(1),$(2),$(MODEXT),-$(MODTYPE),$(LIBDIR))
+make_module = $(call make_target,$(1),$(2),$(LIBEXT),-$(LIBTYPE),$(MODULEDIR))
+make_shared = $(call make_target,$(1),$(2),$(MODEXT),-$(MODTYPE),$(LIBDIR))
 
 # Evaluate library
 define have_lib
index a0317f48bc029b637313c04b20ceab4c8763c8be..0bd103f25a94c6ee24c55efaa293b4f1e7ad0df0 100644 (file)
@@ -52,6 +52,8 @@ static PyObject* init(PyObject* self, PyObject* args)
        #define CACHE_SIZE 100*1024
        test_mm_ctx_init(&global_mm);
        kr_context_init(&global_context, &global_mm);
+       kr_context_register(&global_context, "iterate");
+       kr_context_register(&global_context, "itercache");
        global_tmpdir = test_tmpdir_create();
        assert(global_tmpdir);
        global_context.cache = kr_cache_open(global_tmpdir, &global_mm, CACHE_SIZE);
similarity index 50%
rename from lib/layer/stats.h
rename to tests/test_utils.c
index d66d1dc58ff669c49f3370ae57c2cfff4cad770e..f123a9aace9bbf63546af98c6037adfcaab2ca6c 100644 (file)
@@ -1,4 +1,4 @@
-/*  Copyright (C) 2014 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/*  Copyright (C) 2015 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
 
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
     along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#pragma once
+#include "tests/test.h"
+#include <cmocka.h>
 
-#include "lib/layer.h"
+#include "lib/utils.h"
 
-/* Processing module implementation. */
-const knot_layer_api_t *layer_stats_module(void);
-#define LAYER_STATS layer_stats_module()
+static void test_strcatdup(void **state)
+{
+       auto_free char *empty_res = kr_strcatdup(0);
+       assert_null(empty_res);
+
+       auto_free char *null_res = kr_strcatdup(1, NULL);
+       assert_null(null_res);
+
+       auto_free char *nullcat_res = kr_strcatdup(2, NULL, "beef");
+       assert_string_equal(nullcat_res, "beef");
+
+       auto_free char *multi_res = kr_strcatdup(3, "need", "beef", "dead");
+       assert_string_equal(multi_res, "needbeefdead");
+}
+
+int main(void)
+{
+       const UnitTest tests[] = {
+               unit_test(test_strcatdup),
+       };
+
+       return run_tests(tests);
+}
index a42c9eb4c936f558e32755a9c369e00689c74ddf..43c35e6ce6e84490f0fd6510f973757a1d10b2b5 100644 (file)
@@ -3,6 +3,7 @@
 #
 
 tests_BIN := \
+       test_utils \
        test_context \
        test_rplan \
        test_cache \
@@ -36,7 +37,7 @@ $(eval $(call make_lib,libmock_calls,tests))
 _test_integration_SOURCES := tests/test_integration.c
 _test_integration_LIBS := -Wl,-rpath,tests -Ltests -lmock_calls $(libmock_calls_LIBS)
 _test_integration_DEPEND := libmock_calls
-$(eval $(call make_module,_test_integration,tests))
+$(eval $(call make_shared,_test_integration,tests))
 
 # Preload mock library
 ifeq ($(PLATFORM),Darwin)