helloworld.c revision 369939
1364468Scy/** 2364468Scy * \file 3364468Scy * 4364468Scy * This is an example to show how dynamic libraries can be made to work with 5364468Scy * unbound. To build a .so file simply run: 6364468Scy * gcc -I../.. -shared -Wall -Werror -fpic -o helloworld.so helloworld.c 7364468Scy * And to build for windows, first make unbound with the --with-dynlibmod 8364468Scy * switch, then use this command: 9364468Scy * x86_64-w64-mingw32-gcc -m64 -I../.. -shared -Wall -Werror -fpic 10369939Sgit2svn * -o helloworld.dll helloworld.c -L../.. -l:libunbound.dll.a 11369939Sgit2svn * to cross-compile a 64-bit Windows DLL. The libunbound.dll.a is produced 12369939Sgit2svn * by the compile step that makes unbound.exe and allows the dynlib dll to 13369939Sgit2svn * access definitions in unbound.exe. 14364468Scy */ 15364468Scy 16364468Scy#include "../../config.h" 17364468Scy#include "../../util/module.h" 18364468Scy#include "../../sldns/parseutil.h" 19364468Scy#include "../dynlibmod.h" 20364468Scy 21364468Scy/* Declare the EXPORT macro that expands to exporting the symbol for DLLs when 22364468Scy * compiling for Windows. All procedures marked with EXPORT in this example are 23364468Scy * called directly by the dynlib module and must be present for the module to 24364468Scy * load correctly. */ 25364468Scy#ifdef HAVE_WINDOWS_H 26364468Scy#define EXPORT __declspec(dllexport) 27364468Scy#else 28364468Scy#define EXPORT 29364468Scy#endif 30364468Scy 31364468Scy/* Forward declare a callback, implemented at the bottom of this file */ 32364468Scyint reply_callback(struct query_info* qinfo, 33364468Scy struct module_qstate* qstate, struct reply_info* rep, int rcode, 34364468Scy struct edns_data* edns, struct edns_option** opt_list_out, 35369939Sgit2svn struct comm_reply* repinfo, struct regional* region, 36369939Sgit2svn struct timeval* start_time, int id, void* callback); 37364468Scy 38364468Scy/* Init is called when the module is first loaded. It should be used to set up 39364468Scy * the environment for this module and do any other initialisation required. */ 40364468ScyEXPORT int init(struct module_env* env, int id) { 41364468Scy log_info("dynlib: hello world from init"); 42364468Scy struct dynlibmod_env* de = (struct dynlibmod_env*) env->modinfo[id]; 43364468Scy de->inplace_cb_register_wrapped(&reply_callback, 44364468Scy inplace_cb_reply, 45364468Scy NULL, env, id); 46364468Scy struct dynlibmod_env* local_env = env->modinfo[id]; 47364468Scy local_env->dyn_env = NULL; 48364468Scy return 1; 49364468Scy} 50364468Scy 51364468Scy/* Deinit is run as the program is shutting down. It should be used to clean up 52364468Scy * the environment and any left over data. */ 53364468ScyEXPORT void deinit(struct module_env* env, int id) { 54364468Scy log_info("dynlib: hello world from deinit"); 55364468Scy struct dynlibmod_env* de = (struct dynlibmod_env*) env->modinfo[id]; 56364468Scy de->inplace_cb_delete_wrapped(env, inplace_cb_reply, id); 57364468Scy if (de->dyn_env != NULL) free(de->dyn_env); 58364468Scy} 59364468Scy 60364468Scy/* Operate is called every time a query passes by this module. The event can be 61364468Scy * used to determine which direction in the module chain it came from. */ 62364468ScyEXPORT void operate(struct module_qstate* qstate, enum module_ev event, 63364468Scy int id, struct outbound_entry* entry) { 64364468Scy log_info("dynlib: hello world from operate"); 65364468Scy log_info("dynlib: incoming query: %s %s(%d) %s(%d)", 66364468Scy qstate->qinfo.qname, 67364468Scy sldns_lookup_by_id(sldns_rr_classes, qstate->qinfo.qclass)->name, 68364468Scy qstate->qinfo.qclass, 69364468Scy sldns_rr_descript(qstate->qinfo.qtype)->_name, 70364468Scy qstate->qinfo.qtype); 71364468Scy if (event == module_event_new || event == module_event_pass) { 72364468Scy qstate->ext_state[id] = module_wait_module; 73364468Scy struct dynlibmod_env* env = qstate->env->modinfo[id]; 74364468Scy if (env->dyn_env == NULL) { 75364468Scy env->dyn_env = calloc(3, sizeof(int)); 76364468Scy ((int *)env->dyn_env)[0] = 42; 77364468Scy ((int *)env->dyn_env)[1] = 102; 78364468Scy ((int *)env->dyn_env)[2] = 192; 79364468Scy } else { 80364468Scy log_err("dynlib: already has data!"); 81364468Scy qstate->ext_state[id] = module_error; 82364468Scy } 83364468Scy } else if (event == module_event_moddone) { 84364468Scy qstate->ext_state[id] = module_finished; 85364468Scy } else { 86364468Scy qstate->ext_state[id] = module_error; 87364468Scy } 88364468Scy} 89364468Scy 90364468Scy/* Inform super is called when a query is completed or errors out, but only if 91364468Scy * a sub-query has been registered to it by this module. Look at 92364468Scy * mesh_attach_sub in services/mesh.h to see how this is done. */ 93364468ScyEXPORT void inform_super(struct module_qstate* qstate, int id, 94364468Scy struct module_qstate* super) { 95364468Scy log_info("dynlib: hello world from inform_super"); 96364468Scy} 97364468Scy 98364468Scy/* Clear is called once a query is complete and the response has been sent 99364468Scy * back. It is used to clear up any per-query allocations. */ 100364468ScyEXPORT void clear(struct module_qstate* qstate, int id) { 101364468Scy log_info("dynlib: hello world from clear"); 102364468Scy struct dynlibmod_env* env = qstate->env->modinfo[id]; 103364468Scy if (env->dyn_env != NULL) { 104364468Scy free(env->dyn_env); 105364468Scy env->dyn_env = NULL; 106364468Scy } 107364468Scy} 108364468Scy 109364468Scy/* Get mem is called when Unbound is printing performance information. This 110364468Scy * only happens explicitly and is only used to show memory usage to the user. */ 111364468ScyEXPORT size_t get_mem(struct module_env* env, int id) { 112364468Scy log_info("dynlib: hello world from get_mem"); 113364468Scy return 0; 114364468Scy} 115364468Scy 116364468Scy/* The callback that was forward declared earlier. It is registered in the init 117364468Scy * procedure to run when a query is being replied to. */ 118364468Scyint reply_callback(struct query_info* qinfo, 119364468Scy struct module_qstate* qstate, struct reply_info* rep, int rcode, 120364468Scy struct edns_data* edns, struct edns_option** opt_list_out, 121369939Sgit2svn struct comm_reply* repinfo, struct regional* region, 122369939Sgit2svn struct timeval* start_time, int id, void* callback) { 123364468Scy log_info("dynlib: hello world from callback"); 124364468Scy struct dynlibmod_env* env = qstate->env->modinfo[id]; 125364468Scy if (env->dyn_env != NULL) { 126364468Scy log_info("dynlib: numbers gotten from query: %d, %d, and %d", 127364468Scy ((int *)env->dyn_env)[0], 128364468Scy ((int *)env->dyn_env)[1], 129364468Scy ((int *)env->dyn_env)[2]); 130364468Scy } 131364468Scy return 0; 132364468Scy} 133