From: PMunch Date: Mon, 21 Oct 2019 12:20:33 +0000 (+0200) Subject: Improve dynlib module and add documentation X-Git-Tag: release-1.11.0~45^2^2~6 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8eeb910e3d07f1a1b1f540ffc0fc34c5c2097f8f;p=thirdparty%2Funbound.git Improve dynlib module and add documentation 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. --- diff --git a/daemon/remote.c b/daemon/remote.c index 1689154f5..21ab2f3bc 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -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; diff --git a/doc/example.conf.in b/doc/example.conf.in index 9d8edbf9e..ab6b43baa 100644 --- a/doc/example.conf.in +++ b/doc/example.conf.in @@ -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. diff --git a/doc/unbound.conf.5.in b/doc/unbound.conf.5.in index b7ff72326..434467995 100644 --- a/doc/unbound.conf.5.in +++ b/doc/unbound.conf.5.in @@ -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 File with trusted keys for validation. Both DS and DNSKEY entries can appear @@ -1782,6 +1784,22 @@ directory. .B python\-script: \fI\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\fR +The dynamic library file to load. .SS "DNS64 Module Options" .LP The dns64 module must be configured in the \fBmodule\-config:\fR "dns64 diff --git a/dynlibmod/dynlibmod.c b/dynlibmod/dynlibmod.c index 47d315306..3592f7de7 100644 --- a/dynlibmod/dynlibmod.c +++ b/dynlibmod/dynlibmod.c @@ -5,6 +5,7 @@ #if HAVE_WINDOWS_H #include +#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 +#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); } /** diff --git a/dynlibmod/dynlibmod.h b/dynlibmod/dynlibmod.h index ac5d737b4..1d826a1c8 100644 --- a/dynlibmod/dynlibmod.h +++ b/dynlibmod/dynlibmod.h @@ -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. * diff --git a/dynlibmod/examples/helloworld.c b/dynlibmod/examples/helloworld.c index 76c1df215..6479d8460 100644 --- a/dynlibmod/examples/helloworld.c +++ b/dynlibmod/examples/helloworld.c @@ -17,17 +17,15 @@ #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; } diff --git a/libunbound/unbound.h b/libunbound/unbound.h index 682ba5530..0527d7b7d 100644 --- a/libunbound/unbound.h +++ b/libunbound/unbound.h @@ -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; }; diff --git a/smallapp/unbound-control.c b/smallapp/unbound-control.c index 01e2385fa..c074b782f 100644 --- a/smallapp/unbound-control.c +++ b/smallapp/unbound-control.c @@ -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); diff --git a/util/shm_side/shm_main.c b/util/shm_side/shm_main.c index a783c099b..0842b9b3b 100644 --- a/util/shm_side/shm_main.c +++ b/util/shm_side/shm_main.c @@ -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 }