]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
Improve dynlib module and add documentation
authorPMunch <peterme@peterme.net>
Mon, 21 Oct 2019 12:20:33 +0000 (14:20 +0200)
committerPMunch <peterme@peterme.net>
Mon, 21 Oct 2019 12:20:33 +0000 (14:20 +0200)
Dynamic library module is now only a thin wrapper that loads dynamic
libraries and forwards all function calls directly to the loaded module.
This meant adding get_mem and clear, and get_mem calls have been added
in the expected places.

Documentation has also been added to the example.conf and the
unbound.conf manpage.

daemon/remote.c
doc/example.conf.in
doc/unbound.conf.5.in
dynlibmod/dynlibmod.c
dynlibmod/dynlibmod.h
dynlibmod/examples/helloworld.c
libunbound/unbound.h
smallapp/unbound-control.c
util/shm_side/shm_main.c

index 1689154f5721cf808c70e36b028b8f8bb7c7f225..21ab2f3bc421715c5d3018c20268321c77ee0b01 100644 (file)
@@ -803,6 +803,9 @@ print_mem(RES* ssl, struct worker* worker, struct daemon* daemon,
        size_t dnscrypt_shared_secret = 0;
        size_t dnscrypt_nonce = 0;
 #endif /* USE_DNSCRYPT */
+#ifdef WITH_DYNLIBMODULE
+    size_t dynlib = 0;
+#endif /* WITH_DYNLIBMODULE */
        msg = slabhash_get_mem(daemon->env->msg_cache);
        rrset = slabhash_get_mem(&daemon->env->rrset_cache->table);
        val = mod_get_mem(&worker->env, "validator");
@@ -821,6 +824,9 @@ print_mem(RES* ssl, struct worker* worker, struct daemon* daemon,
                dnscrypt_nonce = slabhash_get_mem(daemon->dnscenv->nonces_cache);
        }
 #endif /* USE_DNSCRYPT */
+#ifdef WITH_DYNLIBMODULE
+    dynlib = mod_get_mem(&worker->env, "dynlib");
+#endif /* WITH_DYNLIBMODULE */
 
        if(!print_longnum(ssl, "mem.cache.rrset"SQ, rrset))
                return 0;
@@ -848,6 +854,10 @@ print_mem(RES* ssl, struct worker* worker, struct daemon* daemon,
                        dnscrypt_nonce))
                return 0;
 #endif /* USE_DNSCRYPT */
+#ifdef WITH_DYNLIBMODULE
+       if(!print_longnum(ssl, "mem.mod.dynlibmod"SQ, dynlib))
+               return 0;
+#endif /* WITH_DYNLIBMODULE */
        if(!print_longnum(ssl, "mem.streamwait"SQ,
                (size_t)s->svr.mem_stream_wait))
                return 0;
index 9d8edbf9eade7be3c68c88127587d20154270a21..ab6b43baae3e0829a08e5ca3adb07814be604d91 100644 (file)
@@ -837,6 +837,16 @@ python:
        # Script file to load
        # python-script: "@UNBOUND_SHARE_DIR@/ubmodule-tst.py"
 
+# Dynamic library config section. To enable:
+# o use --with-dynlibmodule to configure before compiling.
+# o list dynlib in the module-config string (above) to enable.
+#   It can be placed anywhere, the dynlib module is only a very thin wrapper
+#   to load modules dynamically.
+# o and give a dynlib-file to run.
+dynlib:
+       # Script file to load
+       # dynlib-file: "@UNBOUND_SHARE_DIR@/dynlib.so"
+
 # Remote control config section.
 remote-control:
        # Enable remote control with unbound-control(8) here.
index b7ff7232638ae1d9fbd599bd0b2b96b1cbd214c6..434467995f4f1088a8309dc98826f5fe9d0af88b 100644 (file)
@@ -940,7 +940,9 @@ EDNS client subnet support the default is "subnetcache validator iterator".
 Most modules that need to be listed here have to be listed at the beginning
 of the line.  The cachedb module has to be listed just before the iterator.
 The python module can be listed in different places, it then processes the
-output of the module it is just before.
+output of the module it is just before. The dynlib module can be listed pretty
+much anywhere, it is only a very thin wrapper that allows dynamic libraries to
+run in its place.
 .TP
 .B trust\-anchor\-file: \fI<filename>
 File with trusted keys for validation. Both DS and DNSKEY entries can appear
@@ -1782,6 +1784,22 @@ directory.
 .B python\-script: \fI<python file>\fR
 The script file to load. Repeat this option for every python module instance
 added to the \fBmodule\-config:\fR option.
+.SS "Dynamic Library Module Options"
+.LP
+The
+.B dynlib:
+clause gives the settings for the \fIdynlib\fR(1) module.  This module is only
+a very small wrapper that allows dynamic modules to be loaded on runtime
+instead of being compiled into the application. To enable the dynlib module it
+has to be compiled into the daemon, and the word "dynlib" has to be put in the
+\fBmodule\-config:\fR option.
+.LP
+The \fBdynlib\-file:\fR path should be specified as an absolute path relative
+to the new path set by \fBchroot:\fR option, or as a relative path to the
+working directory.
+.TP
+.B dynlib\-file: \fI<dynlib file>\fR
+The dynamic library file to load.
 .SS "DNS64 Module Options"
 .LP
 The dns64 module must be configured in the \fBmodule\-config:\fR "dns64
index 47d315306c8f23c3bca475d5fabd357fbd5f2a1e..3592f7de77edc5425d06e7c28a50c9920bb1f135 100644 (file)
@@ -5,6 +5,7 @@
 
 #if HAVE_WINDOWS_H
 #include <windows.h>
+#define __DYNMOD HMODULE
 #define __DYNSYM FARPROC
 #define __LOADSYM GetProcAddress
 void log_dlerror() {
@@ -25,43 +26,39 @@ void log_dlerror() {
         ))
     {
         DWORD dwBytesWritten;
-
-        //
-        // Output message string on stderr.
-        //
-        log_info("dynlibmod: %s (%ld)", MessageBuffer, dwLastError);
-        //WriteFile(
-        //    GetStdHandle(STD_ERROR_HANDLE),
-        //    MessageBuffer,
-        //    dwBufferLength,
-        //    &dwBytesWritten,
-        //    NULL
-        //    );
-
-        //
-        // Free the buffer allocated by the system.
-        //
+        log_err("dynlibmod: %s (%ld)", MessageBuffer, dwLastError);
         LocalFree(MessageBuffer);
     }
 
 }
+HMODULE open_library(const char* fname) {
+    return LoadLibrary(fname);
+}
 #else
 #include <dlfcn.h>
+#define __DYNMOD void*
 #define __DYNSYM void*
 #define __LOADSYM dlsym
 void log_dlerror() {
     log_err("dynlibmod: %s", dlerror());
 }
+void* open_library(const char* fname) {
+    return dlopen(fname, RTLD_LAZY | RTLD_GLOBAL);
+}
 #endif
 
+
 /**
  * Global state for the module.
  */
 
-typedef int (*func_init_t)(int, struct config_file*);
-typedef int (*func_deinit_t)(int);
-typedef int (*func_operate_t)(int, enum module_ev event, struct module_qstate* qstate, void*);
-typedef int (*func_inform_t)(int, struct module_qstate* qstate, struct module_qstate* super, void*);
+typedef void (*func_init_t)(struct module_env*, int);
+typedef void (*func_deinit_t)(struct module_env*, int);
+typedef void (*func_operate_t)(struct module_qstate*, enum module_ev, int, struct outbound_entry*);
+typedef void (*func_inform_t)(struct module_qstate*, int, struct module_qstate*);
+typedef void (*func_clear_t)(struct module_qstate*, int);
+typedef size_t (*func_get_mem_t)(struct module_env*, int);
+
 struct dynlibmod_env {
 
        /** Dynamic library filename. */
@@ -75,20 +72,19 @@ struct dynlibmod_env {
        func_operate_t func_operate;
        /** Module super_inform function */
        func_inform_t func_inform;
+       /** Module clear function */
+       func_clear_t func_clear;
+       /** Module get_mem function */
+       func_get_mem_t func_get_mem;
 
        /** Module qstate. */
        struct module_qstate* qstate;
 };
 
-struct dynlibmod_qstate {
-
-       /** Module per query data. */
-       void* data;
-};
-
 /** dynlib module init */
 int dynlibmod_init(struct module_env* env, int id) {
     struct dynlibmod_env* de = (struct dynlibmod_env*)calloc(1, sizeof(struct dynlibmod_env));
+    __DYNMOD dynamic_library;
     if (!de)
     {
         log_err("dynlibmod: malloc failure");
@@ -102,59 +98,63 @@ int dynlibmod_init(struct module_env* env, int id) {
         log_err("dynlibmod: no dynamic library given.");
         return 0;
     }
-    log_info("Trying to load library %s", de->fname);
-#ifndef HAVE_WINDOWS_H
-    void* dynamic_library = dlopen(de->fname, RTLD_LAZY | RTLD_GLOBAL);
-#else
-    HMODULE dynamic_library = LoadLibrary(de->fname);
-#endif
+    verbose(VERB_ALGO, "dynlibmod: Trying to load library %s", de->fname);
+    dynamic_library = open_library(de->fname);
     if (dynamic_library == NULL) {
         log_dlerror();
-        log_err("dynlibmod: unable to load dynamic library.");
+        log_err("dynlibmod: unable to load dynamic library \"%s\".", de->fname);
         return 0;
     } else {
         __DYNSYM initializer = __LOADSYM(dynamic_library,"init");
         if (initializer == NULL) {
-            log_err("dynlibmod: unable to load init procedure from dynamic library.");
-#ifndef HAVE_WINDOWS_H
-            log_err("dynlibmod: %s", dlerror());
-#endif
+            log_dlerror();
+            log_err("dynlibmod: unable to load init procedure from dynamic library \"%s\".", de->fname);
             return 0;
         } else {
             de->func_init = (func_init_t) initializer;
         }
         __DYNSYM deinitializer = __LOADSYM(dynamic_library,"deinit");
         if (deinitializer == NULL) {
-            log_err("dynlibmod: unable to load deinit procedure from dynamic library.");
-#ifndef HAVE_WINDOWS_H
-            log_err("dynlibmod: %s", dlerror());
-#endif
+            log_dlerror();
+            log_err("dynlibmod: unable to load deinit procedure from dynamic library \"%s\".", de->fname);
             return 0;
         } else {
             de->func_deinit = (func_deinit_t) deinitializer;
         }
         __DYNSYM operate = __LOADSYM(dynamic_library,"operate");
         if (operate == NULL) {
-            log_err("dynlibmod: unable to load operate procedure from dynamic library.");
-#ifndef HAVE_WINDOWS_H
-            log_err("dynlibmod: %s", dlerror());
-#endif
+            log_dlerror();
+            log_err("dynlibmod: unable to load operate procedure from dynamic library \"%s\".", de->fname);
             return 0;
         } else {
             de->func_operate = (func_operate_t) operate;
         }
         __DYNSYM inform = __LOADSYM(dynamic_library,"inform_super");
         if (inform == NULL) {
-            log_err("dynlibmod: unable to load inform_super procedure from dynamic library.");
-#ifndef HAVE_WINDOWS_H
-            log_err("dynlibmod: %s", dlerror());
-#endif
+            log_dlerror();
+            log_err("dynlibmod: unable to load inform_super procedure from dynamic library \"%s\".", de->fname);
             return 0;
         } else {
             de->func_inform = (func_inform_t) inform;
         }
+        __DYNSYM clear = __LOADSYM(dynamic_library,"clear");
+        if (clear == NULL) {
+            log_dlerror();
+            log_err("dynlibmod: unable to load clear procedure from dynamic library \"%s\".", de->fname);
+            return 0;
+        } else {
+            de->func_clear = (func_clear_t) clear;
+        }
+        __DYNSYM get_mem = __LOADSYM(dynamic_library,"get_mem");
+        if (get_mem == NULL) {
+            log_dlerror();
+            log_err("dynlibmod: unable to load get_mem procedure from dynamic library \"%s\".", de->fname);
+            return 0;
+        } else {
+            de->func_get_mem = (func_get_mem_t) get_mem;
+        }
     }
-    de->func_init(id, env->cfg);
+    de->func_init(env, id);
     return 1;
 }
 
@@ -163,7 +163,7 @@ void dynlibmod_deinit(struct module_env* env, int id) {
     struct dynlibmod_env* de = env->modinfo[id];
     if(de == NULL)
         return;
-    de->func_deinit(id);
+    de->func_deinit(env, id);
     de->fname = NULL;
     free(de);
 }
@@ -172,44 +172,23 @@ void dynlibmod_deinit(struct module_env* env, int id) {
 void dynlibmod_operate(struct module_qstate* qstate, enum module_ev event,
     int id, struct outbound_entry* outbound) {
     struct dynlibmod_env* de = qstate->env->modinfo[id];
-    struct dynlibmod_qstate* dq = (struct dynlibmod_qstate*)qstate->minfo[id];
 
-    void * data = dq == NULL ? NULL : dq->data;
-    int ret = de->func_operate(id, event, qstate, data);
-    if (ret != 1) {
-        log_err("dynlibmod: dynamic library returned bad code from operate %d.", ret);
-        qstate->ext_state[id] = module_error;
-    }
+    de->func_operate(qstate, event, id, outbound);
 }
 
 /** dynlib module  */
 void dynlibmod_inform_super(struct module_qstate* qstate, int id,
     struct module_qstate* super) {
     struct dynlibmod_env* de = qstate->env->modinfo[id];
-    struct dynlibmod_qstate* dq = (struct dynlibmod_qstate*)qstate->minfo[id];
 
-    void * data = dq == NULL ? NULL : dq->data;
-    int ret = de->func_inform(id, qstate, super, data);
-    if (ret != 1) {
-        log_err("dynlibmod: dynamic library returned bad code from inform_super %d.", ret);
-        qstate->ext_state[id] = module_error;
-    }
+    de->func_inform(qstate, id, super);
 }
 
 /** dynlib module cleanup query state */
 void dynlibmod_clear(struct module_qstate* qstate, int id) {
-    struct dynlibmod_qstate* dq;
-    if (qstate == NULL)
-        return;
-
-    dq = (struct dynlibmod_qstate*)qstate->minfo[id];
-    verbose(VERB_ALGO, "dynlibmod: clear, id: %d, dq:%p", id, dq);
-    if(dq != NULL) {
-        /* Free qstate */
-        free(dq);
-    }
+    struct dynlibmod_env* de = qstate->env->modinfo[id];
 
-    qstate->minfo[id] = NULL;
+    de->func_clear(qstate, id);
 }
 
 /** dynlib module alloc size routine */
@@ -218,7 +197,9 @@ size_t dynlibmod_get_mem(struct module_env* env, int id) {
     verbose(VERB_ALGO, "dynlibmod: get_mem, id: %d, de:%p", id, de);
     if(!de)
         return 0;
-    return sizeof(*de);
+
+    size_t size = de->func_get_mem(env, id);
+    return size + sizeof(*de);
 }
 
 /**
index ac5d737b4650eeb3dd925260622e1b1b6ea9ed86..1d826a1c882d642b5af9c7132d37c7d3819791c3 100644 (file)
@@ -1,8 +1,7 @@
 /*
  * dynlibmod.h: module header file
  * 
- * Copyright (c) 2009, Zdenek Vasicek (vasicek AT fit.vutbr.cz)
- *                     Marek Vavrusa  (xvavru00 AT stud.fit.vutbr.cz)
+ * Copyright (c) 2019, Peter Munch-Ellingsen (peterme AT peterme.net)
  *
  * This software is open source.
  * 
index 76c1df215550b8564201306c43988fe99a27a06a..6479d84601597f03ee2d697b4dc43b201dbc1303 100644 (file)
 #define EXPORT
 #endif
 
-EXPORT int init(int id, struct config_file* cfg) {
+EXPORT void init(struct module_env* env, int id) {
     log_info("Hello world from init");
-    return 1;
 }
 
-EXPORT int deinit(int id) {
+EXPORT void deinit(struct module_env* env, int id) {
     log_info("Hello world from deinit");
-    return 1;
 }
 
-EXPORT int operate(int id, enum module_ev event, struct module_qstate* qstate, void* data) {
+EXPORT void operate(struct module_qstate* qstate, enum module_ev event, int id, struct outbound_entry* entry) {
     log_info("Hello world from operate");
     if (event == module_event_new || event == module_event_pass) {
         qstate->ext_state[id] = module_wait_module;
@@ -36,10 +34,17 @@ EXPORT int operate(int id, enum module_ev event, struct module_qstate* qstate, v
     } else {
         qstate->ext_state[id] = module_error;
     }
-    return 1;
 }
 
-EXPORT int inform_super(int id, struct module_qstate* qstate, struct module_qstate* super, void* data) {
+EXPORT void inform_super(struct module_qstate* qstate, int id, struct module_qstate* super) {
     log_info("Hello world from inform_super");
-    return 1;
+}
+
+EXPORT void clear(struct module_qstate* qstate, int id) {
+    log_info("Hello world from clear");
+}
+
+EXPORT size_t get_mem(struct module_env* env, int id) {
+    log_info("Hello world from get_mem");
+    return 0;
 }
index 682ba55308c6e09ad3491ca12f0098848dab3093..0527d7b7daa70416ceb08c8f7d53725aec6ed5aa 100644 (file)
@@ -641,6 +641,7 @@ struct ub_shm_stat_info {
                long long respip;
                long long dnscrypt_shared_secret;
                long long dnscrypt_nonce;
+               long long dynlib;
        } mem;
 };
 
index 01e2385faab71331c5c066ef2f2f5a22a2bb24e3..c074b782f3657420c354ef11feee14d7b3525fee 100644 (file)
@@ -261,6 +261,9 @@ static void print_mem(struct ub_shm_stat_info* shm_stat,
 #ifdef USE_IPSECMOD
        PR_LL("mem.mod.ipsecmod", shm_stat->mem.ipsecmod);
 #endif
+#ifdef WITH_DYNLIBMODULE
+       PR_LL("mem.mod.dynlib", shm_stat->mem.dynlib);
+#endif
 #ifdef USE_DNSCRYPT
        PR_LL("mem.cache.dnscrypt_shared_secret",
                shm_stat->mem.dnscrypt_shared_secret);
index a783c099b5a489b0f27dfee9a3f4959f57ec0b04..0842b9b3b75f561dc6f11e78f10ddbe0e5f34d07 100644 (file)
@@ -280,6 +280,10 @@ void shm_main_run(struct worker *worker)
 #ifdef USE_IPSECMOD
                shm_stat->mem.ipsecmod = (long long)mod_get_mem(&worker->env,
                        "ipsecmod");
+#endif
+#ifdef WITH_DYNLIBMODULE
+               shm_stat->mem.dynlib = (long long)mod_get_mem(&worker->env,
+                       "dynlib");
 #endif
        }