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