1*25039b37SCy Schubert /** 2*25039b37SCy Schubert * \file 3*25039b37SCy Schubert * 4*25039b37SCy Schubert * This is an example to show how dynamic libraries can be made to work with 5*25039b37SCy Schubert * unbound. To build a .so file simply run: 6*25039b37SCy Schubert * gcc -I../.. -shared -Wall -Werror -fpic -o helloworld.so helloworld.c 7*25039b37SCy Schubert * And to build for windows, first make unbound with the --with-dynlibmod 8*25039b37SCy Schubert * switch, then use this command: 9*25039b37SCy Schubert * x86_64-w64-mingw32-gcc -m64 -I../.. -shared -Wall -Werror -fpic 10*25039b37SCy Schubert * -o helloworld.dll helloworld.c -L../.. -l:libunbound.a 11*25039b37SCy Schubert * to cross-compile a 64-bit Windows DLL. 12*25039b37SCy Schubert */ 13*25039b37SCy Schubert 14*25039b37SCy Schubert #include "../../config.h" 15*25039b37SCy Schubert #include "../../util/module.h" 16*25039b37SCy Schubert #include "../../sldns/parseutil.h" 17*25039b37SCy Schubert #include "../dynlibmod.h" 18*25039b37SCy Schubert 19*25039b37SCy Schubert /* Declare the EXPORT macro that expands to exporting the symbol for DLLs when 20*25039b37SCy Schubert * compiling for Windows. All procedures marked with EXPORT in this example are 21*25039b37SCy Schubert * called directly by the dynlib module and must be present for the module to 22*25039b37SCy Schubert * load correctly. */ 23*25039b37SCy Schubert #ifdef HAVE_WINDOWS_H 24*25039b37SCy Schubert #define EXPORT __declspec(dllexport) 25*25039b37SCy Schubert #else 26*25039b37SCy Schubert #define EXPORT 27*25039b37SCy Schubert #endif 28*25039b37SCy Schubert 29*25039b37SCy Schubert /* Forward declare a callback, implemented at the bottom of this file */ 30*25039b37SCy Schubert int reply_callback(struct query_info* qinfo, 31*25039b37SCy Schubert struct module_qstate* qstate, struct reply_info* rep, int rcode, 32*25039b37SCy Schubert struct edns_data* edns, struct edns_option** opt_list_out, 33*25039b37SCy Schubert struct comm_reply* repinfo, struct regional* region, int id, 34*25039b37SCy Schubert void* callback); 35*25039b37SCy Schubert 36*25039b37SCy Schubert /* Init is called when the module is first loaded. It should be used to set up 37*25039b37SCy Schubert * the environment for this module and do any other initialisation required. */ 38*25039b37SCy Schubert EXPORT int init(struct module_env* env, int id) { 39*25039b37SCy Schubert log_info("dynlib: hello world from init"); 40*25039b37SCy Schubert struct dynlibmod_env* de = (struct dynlibmod_env*) env->modinfo[id]; 41*25039b37SCy Schubert de->inplace_cb_register_wrapped(&reply_callback, 42*25039b37SCy Schubert inplace_cb_reply, 43*25039b37SCy Schubert NULL, env, id); 44*25039b37SCy Schubert struct dynlibmod_env* local_env = env->modinfo[id]; 45*25039b37SCy Schubert local_env->dyn_env = NULL; 46*25039b37SCy Schubert return 1; 47*25039b37SCy Schubert } 48*25039b37SCy Schubert 49*25039b37SCy Schubert /* Deinit is run as the program is shutting down. It should be used to clean up 50*25039b37SCy Schubert * the environment and any left over data. */ 51*25039b37SCy Schubert EXPORT void deinit(struct module_env* env, int id) { 52*25039b37SCy Schubert log_info("dynlib: hello world from deinit"); 53*25039b37SCy Schubert struct dynlibmod_env* de = (struct dynlibmod_env*) env->modinfo[id]; 54*25039b37SCy Schubert de->inplace_cb_delete_wrapped(env, inplace_cb_reply, id); 55*25039b37SCy Schubert if (de->dyn_env != NULL) free(de->dyn_env); 56*25039b37SCy Schubert } 57*25039b37SCy Schubert 58*25039b37SCy Schubert /* Operate is called every time a query passes by this module. The event can be 59*25039b37SCy Schubert * used to determine which direction in the module chain it came from. */ 60*25039b37SCy Schubert EXPORT void operate(struct module_qstate* qstate, enum module_ev event, 61*25039b37SCy Schubert int id, struct outbound_entry* entry) { 62*25039b37SCy Schubert log_info("dynlib: hello world from operate"); 63*25039b37SCy Schubert log_info("dynlib: incoming query: %s %s(%d) %s(%d)", 64*25039b37SCy Schubert qstate->qinfo.qname, 65*25039b37SCy Schubert sldns_lookup_by_id(sldns_rr_classes, qstate->qinfo.qclass)->name, 66*25039b37SCy Schubert qstate->qinfo.qclass, 67*25039b37SCy Schubert sldns_rr_descript(qstate->qinfo.qtype)->_name, 68*25039b37SCy Schubert qstate->qinfo.qtype); 69*25039b37SCy Schubert if (event == module_event_new || event == module_event_pass) { 70*25039b37SCy Schubert qstate->ext_state[id] = module_wait_module; 71*25039b37SCy Schubert struct dynlibmod_env* env = qstate->env->modinfo[id]; 72*25039b37SCy Schubert if (env->dyn_env == NULL) { 73*25039b37SCy Schubert env->dyn_env = calloc(3, sizeof(int)); 74*25039b37SCy Schubert ((int *)env->dyn_env)[0] = 42; 75*25039b37SCy Schubert ((int *)env->dyn_env)[1] = 102; 76*25039b37SCy Schubert ((int *)env->dyn_env)[2] = 192; 77*25039b37SCy Schubert } else { 78*25039b37SCy Schubert log_err("dynlib: already has data!"); 79*25039b37SCy Schubert qstate->ext_state[id] = module_error; 80*25039b37SCy Schubert } 81*25039b37SCy Schubert } else if (event == module_event_moddone) { 82*25039b37SCy Schubert qstate->ext_state[id] = module_finished; 83*25039b37SCy Schubert } else { 84*25039b37SCy Schubert qstate->ext_state[id] = module_error; 85*25039b37SCy Schubert } 86*25039b37SCy Schubert } 87*25039b37SCy Schubert 88*25039b37SCy Schubert /* Inform super is called when a query is completed or errors out, but only if 89*25039b37SCy Schubert * a sub-query has been registered to it by this module. Look at 90*25039b37SCy Schubert * mesh_attach_sub in services/mesh.h to see how this is done. */ 91*25039b37SCy Schubert EXPORT void inform_super(struct module_qstate* qstate, int id, 92*25039b37SCy Schubert struct module_qstate* super) { 93*25039b37SCy Schubert log_info("dynlib: hello world from inform_super"); 94*25039b37SCy Schubert } 95*25039b37SCy Schubert 96*25039b37SCy Schubert /* Clear is called once a query is complete and the response has been sent 97*25039b37SCy Schubert * back. It is used to clear up any per-query allocations. */ 98*25039b37SCy Schubert EXPORT void clear(struct module_qstate* qstate, int id) { 99*25039b37SCy Schubert log_info("dynlib: hello world from clear"); 100*25039b37SCy Schubert struct dynlibmod_env* env = qstate->env->modinfo[id]; 101*25039b37SCy Schubert if (env->dyn_env != NULL) { 102*25039b37SCy Schubert free(env->dyn_env); 103*25039b37SCy Schubert env->dyn_env = NULL; 104*25039b37SCy Schubert } 105*25039b37SCy Schubert } 106*25039b37SCy Schubert 107*25039b37SCy Schubert /* Get mem is called when Unbound is printing performance information. This 108*25039b37SCy Schubert * only happens explicitly and is only used to show memory usage to the user. */ 109*25039b37SCy Schubert EXPORT size_t get_mem(struct module_env* env, int id) { 110*25039b37SCy Schubert log_info("dynlib: hello world from get_mem"); 111*25039b37SCy Schubert return 0; 112*25039b37SCy Schubert } 113*25039b37SCy Schubert 114*25039b37SCy Schubert /* The callback that was forward declared earlier. It is registered in the init 115*25039b37SCy Schubert * procedure to run when a query is being replied to. */ 116*25039b37SCy Schubert int reply_callback(struct query_info* qinfo, 117*25039b37SCy Schubert struct module_qstate* qstate, struct reply_info* rep, int rcode, 118*25039b37SCy Schubert struct edns_data* edns, struct edns_option** opt_list_out, 119*25039b37SCy Schubert struct comm_reply* repinfo, struct regional* region, int id, 120*25039b37SCy Schubert void* callback) { 121*25039b37SCy Schubert log_info("dynlib: hello world from callback"); 122*25039b37SCy Schubert struct dynlibmod_env* env = qstate->env->modinfo[id]; 123*25039b37SCy Schubert if (env->dyn_env != NULL) { 124*25039b37SCy Schubert log_info("dynlib: numbers gotten from query: %d, %d, and %d", 125*25039b37SCy Schubert ((int *)env->dyn_env)[0], 126*25039b37SCy Schubert ((int *)env->dyn_env)[1], 127*25039b37SCy Schubert ((int *)env->dyn_env)[2]); 128*25039b37SCy Schubert } 129*25039b37SCy Schubert return 0; 130*25039b37SCy Schubert } 131