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