1364468Scy/**
2364468Scy * \file
3364468Scy *
4364468Scy * This is an example to show how dynamic libraries can be made to work with
5364468Scy * unbound. To build a .so file simply run:
6364468Scy *   gcc -I../.. -shared -Wall -Werror -fpic  -o helloworld.so helloworld.c
7364468Scy * And to build for windows, first make unbound with the --with-dynlibmod
8364468Scy * switch, then use this command:
9364468Scy *   x86_64-w64-mingw32-gcc -m64 -I../.. -shared -Wall -Werror -fpic
10369939Sgit2svn *      -o helloworld.dll helloworld.c -L../.. -l:libunbound.dll.a
11369939Sgit2svn * to cross-compile a 64-bit Windows DLL.  The libunbound.dll.a is produced
12369939Sgit2svn * by the compile step that makes unbound.exe and allows the dynlib dll to
13369939Sgit2svn * access definitions in unbound.exe.
14364468Scy */
15364468Scy
16364468Scy#include "../../config.h"
17364468Scy#include "../../util/module.h"
18364468Scy#include "../../sldns/parseutil.h"
19364468Scy#include "../dynlibmod.h"
20364468Scy
21364468Scy/* Declare the EXPORT macro that expands to exporting the symbol for DLLs when
22364468Scy * compiling for Windows. All procedures marked with EXPORT in this example are
23364468Scy * called directly by the dynlib module and must be present for the module to
24364468Scy * load correctly. */
25364468Scy#ifdef HAVE_WINDOWS_H
26364468Scy#define EXPORT __declspec(dllexport)
27364468Scy#else
28364468Scy#define EXPORT
29364468Scy#endif
30364468Scy
31364468Scy/* Forward declare a callback, implemented at the bottom of this file */
32364468Scyint reply_callback(struct query_info* qinfo,
33364468Scy    struct module_qstate* qstate, struct reply_info* rep, int rcode,
34364468Scy    struct edns_data* edns, struct edns_option** opt_list_out,
35369939Sgit2svn    struct comm_reply* repinfo, struct regional* region,
36369939Sgit2svn    struct timeval* start_time, int id, void* callback);
37364468Scy
38364468Scy/* Init is called when the module is first loaded. It should be used to set up
39364468Scy * the environment for this module and do any other initialisation required. */
40364468ScyEXPORT int init(struct module_env* env, int id) {
41364468Scy    log_info("dynlib: hello world from init");
42364468Scy    struct dynlibmod_env* de = (struct dynlibmod_env*) env->modinfo[id];
43364468Scy    de->inplace_cb_register_wrapped(&reply_callback,
44364468Scy                                    inplace_cb_reply,
45364468Scy                                    NULL, env, id);
46364468Scy    struct dynlibmod_env* local_env = env->modinfo[id];
47364468Scy    local_env->dyn_env = NULL;
48364468Scy    return 1;
49364468Scy}
50364468Scy
51364468Scy/* Deinit is run as the program is shutting down. It should be used to clean up
52364468Scy * the environment and any left over data. */
53364468ScyEXPORT void deinit(struct module_env* env, int id) {
54364468Scy    log_info("dynlib: hello world from deinit");
55364468Scy    struct dynlibmod_env* de = (struct dynlibmod_env*) env->modinfo[id];
56364468Scy    de->inplace_cb_delete_wrapped(env, inplace_cb_reply, id);
57364468Scy    if (de->dyn_env != NULL) free(de->dyn_env);
58364468Scy}
59364468Scy
60364468Scy/* Operate is called every time a query passes by this module. The event can be
61364468Scy * used to determine which direction in the module chain it came from. */
62364468ScyEXPORT void operate(struct module_qstate* qstate, enum module_ev event,
63364468Scy                    int id, struct outbound_entry* entry) {
64364468Scy    log_info("dynlib: hello world from operate");
65364468Scy    log_info("dynlib: incoming query: %s %s(%d) %s(%d)",
66364468Scy            qstate->qinfo.qname,
67364468Scy            sldns_lookup_by_id(sldns_rr_classes, qstate->qinfo.qclass)->name,
68364468Scy            qstate->qinfo.qclass,
69364468Scy            sldns_rr_descript(qstate->qinfo.qtype)->_name,
70364468Scy            qstate->qinfo.qtype);
71364468Scy    if (event == module_event_new || event == module_event_pass) {
72364468Scy        qstate->ext_state[id] = module_wait_module;
73364468Scy        struct dynlibmod_env* env = qstate->env->modinfo[id];
74364468Scy        if (env->dyn_env == NULL) {
75364468Scy            env->dyn_env = calloc(3, sizeof(int));
76364468Scy            ((int *)env->dyn_env)[0] = 42;
77364468Scy            ((int *)env->dyn_env)[1] = 102;
78364468Scy            ((int *)env->dyn_env)[2] = 192;
79364468Scy        } else {
80364468Scy            log_err("dynlib: already has data!");
81364468Scy            qstate->ext_state[id] = module_error;
82364468Scy        }
83364468Scy    } else if (event == module_event_moddone) {
84364468Scy        qstate->ext_state[id] = module_finished;
85364468Scy    } else {
86364468Scy        qstate->ext_state[id] = module_error;
87364468Scy    }
88364468Scy}
89364468Scy
90364468Scy/* Inform super is called when a query is completed or errors out, but only if
91364468Scy * a sub-query has been registered to it by this module. Look at
92364468Scy * mesh_attach_sub in services/mesh.h to see how this is done. */
93364468ScyEXPORT void inform_super(struct module_qstate* qstate, int id,
94364468Scy                         struct module_qstate* super) {
95364468Scy    log_info("dynlib: hello world from inform_super");
96364468Scy}
97364468Scy
98364468Scy/* Clear is called once a query is complete and the response has been sent
99364468Scy * back. It is used to clear up any per-query allocations. */
100364468ScyEXPORT void clear(struct module_qstate* qstate, int id) {
101364468Scy    log_info("dynlib: hello world from clear");
102364468Scy    struct dynlibmod_env* env = qstate->env->modinfo[id];
103364468Scy    if (env->dyn_env != NULL) {
104364468Scy        free(env->dyn_env);
105364468Scy        env->dyn_env = NULL;
106364468Scy    }
107364468Scy}
108364468Scy
109364468Scy/* Get mem is called when Unbound is printing performance information. This
110364468Scy * only happens explicitly and is only used to show memory usage to the user. */
111364468ScyEXPORT size_t get_mem(struct module_env* env, int id) {
112364468Scy    log_info("dynlib: hello world from get_mem");
113364468Scy    return 0;
114364468Scy}
115364468Scy
116364468Scy/* The callback that was forward declared earlier. It is registered in the init
117364468Scy * procedure to run when a query is being replied to. */
118364468Scyint reply_callback(struct query_info* qinfo,
119364468Scy    struct module_qstate* qstate, struct reply_info* rep, int rcode,
120364468Scy    struct edns_data* edns, struct edns_option** opt_list_out,
121369939Sgit2svn    struct comm_reply* repinfo, struct regional* region,
122369939Sgit2svn    struct timeval* start_time, int id, void* callback) {
123364468Scy    log_info("dynlib: hello world from callback");
124364468Scy    struct dynlibmod_env* env = qstate->env->modinfo[id];
125364468Scy    if (env->dyn_env != NULL) {
126364468Scy        log_info("dynlib: numbers gotten from query: %d, %d, and %d",
127364468Scy            ((int *)env->dyn_env)[0],
128364468Scy            ((int *)env->dyn_env)[1],
129364468Scy            ((int *)env->dyn_env)[2]);
130364468Scy    }
131364468Scy    return 0;
132364468Scy}
133