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