diff options
Diffstat (limited to 'dynlibmod/examples/helloworld.c')
-rw-r--r-- | dynlibmod/examples/helloworld.c | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/dynlibmod/examples/helloworld.c b/dynlibmod/examples/helloworld.c new file mode 100644 index 0000000000000..acb6b5d9bda6a --- /dev/null +++ b/dynlibmod/examples/helloworld.c @@ -0,0 +1,130 @@ +/** + * \file + * + * This is an example to show how dynamic libraries can be made to work with + * unbound. To build a .so file simply run: + * gcc -I../.. -shared -Wall -Werror -fpic -o helloworld.so helloworld.c + * And to build for windows, first make unbound with the --with-dynlibmod + * switch, then use this command: + * x86_64-w64-mingw32-gcc -m64 -I../.. -shared -Wall -Werror -fpic + * -o helloworld.dll helloworld.c -L../.. -l:libunbound.a + * to cross-compile a 64-bit Windows DLL. + */ + +#include "../../config.h" +#include "../../util/module.h" +#include "../../sldns/parseutil.h" +#include "../dynlibmod.h" + +/* Declare the EXPORT macro that expands to exporting the symbol for DLLs when + * compiling for Windows. All procedures marked with EXPORT in this example are + * called directly by the dynlib module and must be present for the module to + * load correctly. */ +#ifdef HAVE_WINDOWS_H +#define EXPORT __declspec(dllexport) +#else +#define EXPORT +#endif + +/* Forward declare a callback, implemented at the bottom of this file */ +int reply_callback(struct query_info* qinfo, + struct module_qstate* qstate, struct reply_info* rep, int rcode, + struct edns_data* edns, struct edns_option** opt_list_out, + struct comm_reply* repinfo, struct regional* region, int id, + void* callback); + +/* Init is called when the module is first loaded. It should be used to set up + * the environment for this module and do any other initialisation required. */ +EXPORT int init(struct module_env* env, int id) { + log_info("dynlib: hello world from init"); + struct dynlibmod_env* de = (struct dynlibmod_env*) env->modinfo[id]; + de->inplace_cb_register_wrapped(&reply_callback, + inplace_cb_reply, + NULL, env, id); + struct dynlibmod_env* local_env = env->modinfo[id]; + local_env->dyn_env = NULL; + return 1; +} + +/* Deinit is run as the program is shutting down. It should be used to clean up + * the environment and any left over data. */ +EXPORT void deinit(struct module_env* env, int id) { + log_info("dynlib: hello world from deinit"); + struct dynlibmod_env* de = (struct dynlibmod_env*) env->modinfo[id]; + de->inplace_cb_delete_wrapped(env, inplace_cb_reply, id); + if (de->dyn_env != NULL) free(de->dyn_env); +} + +/* Operate is called every time a query passes by this module. The event can be + * used to determine which direction in the module chain it came from. */ +EXPORT void operate(struct module_qstate* qstate, enum module_ev event, + int id, struct outbound_entry* entry) { + log_info("dynlib: hello world from operate"); + log_info("dynlib: incoming query: %s %s(%d) %s(%d)", + qstate->qinfo.qname, + sldns_lookup_by_id(sldns_rr_classes, qstate->qinfo.qclass)->name, + qstate->qinfo.qclass, + sldns_rr_descript(qstate->qinfo.qtype)->_name, + qstate->qinfo.qtype); + if (event == module_event_new || event == module_event_pass) { + qstate->ext_state[id] = module_wait_module; + struct dynlibmod_env* env = qstate->env->modinfo[id]; + if (env->dyn_env == NULL) { + env->dyn_env = calloc(3, sizeof(int)); + ((int *)env->dyn_env)[0] = 42; + ((int *)env->dyn_env)[1] = 102; + ((int *)env->dyn_env)[2] = 192; + } else { + log_err("dynlib: already has data!"); + qstate->ext_state[id] = module_error; + } + } else if (event == module_event_moddone) { + qstate->ext_state[id] = module_finished; + } else { + qstate->ext_state[id] = module_error; + } +} + +/* Inform super is called when a query is completed or errors out, but only if + * a sub-query has been registered to it by this module. Look at + * mesh_attach_sub in services/mesh.h to see how this is done. */ +EXPORT void inform_super(struct module_qstate* qstate, int id, + struct module_qstate* super) { + log_info("dynlib: hello world from inform_super"); +} + +/* Clear is called once a query is complete and the response has been sent + * back. It is used to clear up any per-query allocations. */ +EXPORT void clear(struct module_qstate* qstate, int id) { + log_info("dynlib: hello world from clear"); + struct dynlibmod_env* env = qstate->env->modinfo[id]; + if (env->dyn_env != NULL) { + free(env->dyn_env); + env->dyn_env = NULL; + } +} + +/* Get mem is called when Unbound is printing performance information. This + * only happens explicitly and is only used to show memory usage to the user. */ +EXPORT size_t get_mem(struct module_env* env, int id) { + log_info("dynlib: hello world from get_mem"); + return 0; +} + +/* The callback that was forward declared earlier. It is registered in the init + * procedure to run when a query is being replied to. */ +int reply_callback(struct query_info* qinfo, + struct module_qstate* qstate, struct reply_info* rep, int rcode, + struct edns_data* edns, struct edns_option** opt_list_out, + struct comm_reply* repinfo, struct regional* region, int id, + void* callback) { + log_info("dynlib: hello world from callback"); + struct dynlibmod_env* env = qstate->env->modinfo[id]; + if (env->dyn_env != NULL) { + log_info("dynlib: numbers gotten from query: %d, %d, and %d", + ((int *)env->dyn_env)[0], + ((int *)env->dyn_env)[1], + ((int *)env->dyn_env)[2]); + } + return 0; +} |