xref: /freebsd-src/contrib/unbound/dynlibmod/examples/helloworld.c (revision 25039b37d3883b8fdae50475cbea41a255a08ee2)
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