aboutsummaryrefslogtreecommitdiff
path: root/contrib/unbound/dynlibmod/examples/helloworld.c
blob: be21168430a72610b9076e36e849eba4bc8a5872 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/**
 * \file
 *
 * This is an example to show how dynamic libraries can be made to work with
 * unbound. To build a .so file simply run:
 *   gcc -I../.. -shared -Wall -Werror -fpic  -o helloworld.so helloworld.c
 * And to build for windows, first make unbound with the --with-dynlibmod
 * switch, then use this command:
 *   x86_64-w64-mingw32-gcc -m64 -I../.. -shared -Wall -Werror -fpic
 *      -o helloworld.dll helloworld.c -L../.. -l:libunbound.dll.a
 * to cross-compile a 64-bit Windows DLL.  The libunbound.dll.a is produced
 * by the compile step that makes unbound.exe and allows the dynlib dll to
 * access definitions in unbound.exe.
 */

#include "../../config.h"
#include "../../util/module.h"
#include "../../sldns/parseutil.h"
#include "../dynlibmod.h"

/* Declare the EXPORT macro that expands to exporting the symbol for DLLs when
 * compiling for Windows. All procedures marked with EXPORT in this example are
 * called directly by the dynlib module and must be present for the module to
 * load correctly. */
#ifdef HAVE_WINDOWS_H
#define EXPORT __declspec(dllexport)
#else
#define EXPORT
#endif

/* Forward declare a callback, implemented at the bottom of this file */
int 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);

/* Init is called when the module is first loaded. It should be used to set up
 * the environment for this module and do any other initialisation required. */
EXPORT int init(struct module_env* env, int id) {
    log_info("dynlib: hello world from init");
    struct dynlibmod_env* de = (struct dynlibmod_env*) env->modinfo[id];
    de->inplace_cb_register_wrapped(&reply_callback,
                                    inplace_cb_reply,
                                    NULL, env, id);
    struct dynlibmod_env* local_env = env->modinfo[id];
    local_env->dyn_env = NULL;
    return 1;
}

/* Deinit is run as the program is shutting down. It should be used to clean up
 * the environment and any left over data. */
EXPORT void deinit(struct module_env* env, int id) {
    log_info("dynlib: hello world from deinit");
    struct dynlibmod_env* de = (struct dynlibmod_env*) env->modinfo[id];
    de->inplace_cb_delete_wrapped(env, inplace_cb_reply, id);
    if (de->dyn_env != NULL) free(de->dyn_env);
}

/* Operate is called every time a query passes by this module. The event can be
 * used to determine which direction in the module chain it came from. */
EXPORT void operate(struct module_qstate* qstate, enum module_ev event,
                    int id, struct outbound_entry* entry) {
    log_info("dynlib: hello world from operate");
    log_info("dynlib: incoming query: %s %s(%d) %s(%d)",
            qstate->qinfo.qname,
            sldns_lookup_by_id(sldns_rr_classes, qstate->qinfo.qclass)->name,
            qstate->qinfo.qclass,
            sldns_rr_descript(qstate->qinfo.qtype)->_name,
            qstate->qinfo.qtype);
    if (event == module_event_new || event == module_event_pass) {
        qstate->ext_state[id] = module_wait_module;
        struct dynlibmod_env* env = qstate->env->modinfo[id];
        if (env->dyn_env == NULL) {
            env->dyn_env = calloc(3, sizeof(int));
            ((int *)env->dyn_env)[0] = 42;
            ((int *)env->dyn_env)[1] = 102;
            ((int *)env->dyn_env)[2] = 192;
        } else {
            log_err("dynlib: already has data!");
            qstate->ext_state[id] = module_error;
        }
    } else if (event == module_event_moddone) {
        qstate->ext_state[id] = module_finished;
    } else {
        qstate->ext_state[id] = module_error;
    }
}

/* Inform super is called when a query is completed or errors out, but only if
 * a sub-query has been registered to it by this module. Look at
 * mesh_attach_sub in services/mesh.h to see how this is done. */
EXPORT void inform_super(struct module_qstate* qstate, int id,
                         struct module_qstate* super) {
    log_info("dynlib: hello world from inform_super");
}

/* Clear is called once a query is complete and the response has been sent
 * back. It is used to clear up any per-query allocations. */
EXPORT void clear(struct module_qstate* qstate, int id) {
    log_info("dynlib: hello world from clear");
    struct dynlibmod_env* env = qstate->env->modinfo[id];
    if (env->dyn_env != NULL) {
        free(env->dyn_env);
        env->dyn_env = NULL;
    }
}

/* Get mem is called when Unbound is printing performance information. This
 * only happens explicitly and is only used to show memory usage to the user. */
EXPORT size_t get_mem(struct module_env* env, int id) {
    log_info("dynlib: hello world from get_mem");
    return 0;
}

/* The callback that was forward declared earlier. It is registered in the init
 * procedure to run when a query is being replied to. */
int 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) {
    log_info("dynlib: hello world from callback");
    struct dynlibmod_env* env = qstate->env->modinfo[id];
    if (env->dyn_env != NULL) {
        log_info("dynlib: numbers gotten from query: %d, %d, and %d",
            ((int *)env->dyn_env)[0],
            ((int *)env->dyn_env)[1],
            ((int *)env->dyn_env)[2]);
    }
    return 0;
}