125039b37SCy Schubert /**
225039b37SCy Schubert * \file
325039b37SCy Schubert *
425039b37SCy Schubert * This is an example to show how dynamic libraries can be made to work with
525039b37SCy Schubert * unbound. To build a .so file simply run:
625039b37SCy Schubert * gcc -I../.. -shared -Wall -Werror -fpic -o helloworld.so helloworld.c
725039b37SCy Schubert * And to build for windows, first make unbound with the --with-dynlibmod
825039b37SCy Schubert * switch, then use this command:
925039b37SCy Schubert * x86_64-w64-mingw32-gcc -m64 -I../.. -shared -Wall -Werror -fpic
10*f44e67d1SCy Schubert * -o helloworld.dll helloworld.c -L../.. -l:libunbound.dll.a
11*f44e67d1SCy Schubert * to cross-compile a 64-bit Windows DLL. The libunbound.dll.a is produced
12*f44e67d1SCy Schubert * by the compile step that makes unbound.exe and allows the dynlib dll to
13*f44e67d1SCy Schubert * access definitions in unbound.exe.
1425039b37SCy Schubert */
1525039b37SCy Schubert
1625039b37SCy Schubert #include "../../config.h"
1725039b37SCy Schubert #include "../../util/module.h"
1825039b37SCy Schubert #include "../../sldns/parseutil.h"
1925039b37SCy Schubert #include "../dynlibmod.h"
2025039b37SCy Schubert
2125039b37SCy Schubert /* Declare the EXPORT macro that expands to exporting the symbol for DLLs when
2225039b37SCy Schubert * compiling for Windows. All procedures marked with EXPORT in this example are
2325039b37SCy Schubert * called directly by the dynlib module and must be present for the module to
2425039b37SCy Schubert * load correctly. */
2525039b37SCy Schubert #ifdef HAVE_WINDOWS_H
2625039b37SCy Schubert #define EXPORT __declspec(dllexport)
2725039b37SCy Schubert #else
2825039b37SCy Schubert #define EXPORT
2925039b37SCy Schubert #endif
3025039b37SCy Schubert
3125039b37SCy Schubert /* Forward declare a callback, implemented at the bottom of this file */
3225039b37SCy Schubert int reply_callback(struct query_info* qinfo,
3325039b37SCy Schubert struct module_qstate* qstate, struct reply_info* rep, int rcode,
3425039b37SCy Schubert struct edns_data* edns, struct edns_option** opt_list_out,
35*f44e67d1SCy Schubert struct comm_reply* repinfo, struct regional* region,
36*f44e67d1SCy Schubert struct timeval* start_time, int id, void* callback);
3725039b37SCy Schubert
3825039b37SCy Schubert /* Init is called when the module is first loaded. It should be used to set up
3925039b37SCy Schubert * the environment for this module and do any other initialisation required. */
init(struct module_env * env,int id)4025039b37SCy Schubert EXPORT int init(struct module_env* env, int id) {
4125039b37SCy Schubert log_info("dynlib: hello world from init");
4225039b37SCy Schubert struct dynlibmod_env* de = (struct dynlibmod_env*) env->modinfo[id];
4325039b37SCy Schubert de->inplace_cb_register_wrapped(&reply_callback,
4425039b37SCy Schubert inplace_cb_reply,
4525039b37SCy Schubert NULL, env, id);
4625039b37SCy Schubert struct dynlibmod_env* local_env = env->modinfo[id];
4725039b37SCy Schubert local_env->dyn_env = NULL;
4825039b37SCy Schubert return 1;
4925039b37SCy Schubert }
5025039b37SCy Schubert
5125039b37SCy Schubert /* Deinit is run as the program is shutting down. It should be used to clean up
5225039b37SCy Schubert * the environment and any left over data. */
deinit(struct module_env * env,int id)5325039b37SCy Schubert EXPORT void deinit(struct module_env* env, int id) {
5425039b37SCy Schubert log_info("dynlib: hello world from deinit");
5525039b37SCy Schubert struct dynlibmod_env* de = (struct dynlibmod_env*) env->modinfo[id];
5625039b37SCy Schubert de->inplace_cb_delete_wrapped(env, inplace_cb_reply, id);
5725039b37SCy Schubert if (de->dyn_env != NULL) free(de->dyn_env);
5825039b37SCy Schubert }
5925039b37SCy Schubert
6025039b37SCy Schubert /* Operate is called every time a query passes by this module. The event can be
6125039b37SCy Schubert * 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)6225039b37SCy Schubert EXPORT void operate(struct module_qstate* qstate, enum module_ev event,
6325039b37SCy Schubert int id, struct outbound_entry* entry) {
6425039b37SCy Schubert log_info("dynlib: hello world from operate");
6525039b37SCy Schubert log_info("dynlib: incoming query: %s %s(%d) %s(%d)",
6625039b37SCy Schubert qstate->qinfo.qname,
6725039b37SCy Schubert sldns_lookup_by_id(sldns_rr_classes, qstate->qinfo.qclass)->name,
6825039b37SCy Schubert qstate->qinfo.qclass,
6925039b37SCy Schubert sldns_rr_descript(qstate->qinfo.qtype)->_name,
7025039b37SCy Schubert qstate->qinfo.qtype);
7125039b37SCy Schubert if (event == module_event_new || event == module_event_pass) {
7225039b37SCy Schubert qstate->ext_state[id] = module_wait_module;
7325039b37SCy Schubert struct dynlibmod_env* env = qstate->env->modinfo[id];
7425039b37SCy Schubert if (env->dyn_env == NULL) {
7525039b37SCy Schubert env->dyn_env = calloc(3, sizeof(int));
7625039b37SCy Schubert ((int *)env->dyn_env)[0] = 42;
7725039b37SCy Schubert ((int *)env->dyn_env)[1] = 102;
7825039b37SCy Schubert ((int *)env->dyn_env)[2] = 192;
7925039b37SCy Schubert } else {
8025039b37SCy Schubert log_err("dynlib: already has data!");
8125039b37SCy Schubert qstate->ext_state[id] = module_error;
8225039b37SCy Schubert }
8325039b37SCy Schubert } else if (event == module_event_moddone) {
8425039b37SCy Schubert qstate->ext_state[id] = module_finished;
8525039b37SCy Schubert } else {
8625039b37SCy Schubert qstate->ext_state[id] = module_error;
8725039b37SCy Schubert }
8825039b37SCy Schubert }
8925039b37SCy Schubert
9025039b37SCy Schubert /* Inform super is called when a query is completed or errors out, but only if
9125039b37SCy Schubert * a sub-query has been registered to it by this module. Look at
9225039b37SCy Schubert * 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)9325039b37SCy Schubert EXPORT void inform_super(struct module_qstate* qstate, int id,
9425039b37SCy Schubert struct module_qstate* super) {
9525039b37SCy Schubert log_info("dynlib: hello world from inform_super");
9625039b37SCy Schubert }
9725039b37SCy Schubert
9825039b37SCy Schubert /* Clear is called once a query is complete and the response has been sent
9925039b37SCy Schubert * back. It is used to clear up any per-query allocations. */
clear(struct module_qstate * qstate,int id)10025039b37SCy Schubert EXPORT void clear(struct module_qstate* qstate, int id) {
10125039b37SCy Schubert log_info("dynlib: hello world from clear");
10225039b37SCy Schubert struct dynlibmod_env* env = qstate->env->modinfo[id];
10325039b37SCy Schubert if (env->dyn_env != NULL) {
10425039b37SCy Schubert free(env->dyn_env);
10525039b37SCy Schubert env->dyn_env = NULL;
10625039b37SCy Schubert }
10725039b37SCy Schubert }
10825039b37SCy Schubert
10925039b37SCy Schubert /* Get mem is called when Unbound is printing performance information. This
11025039b37SCy Schubert * only happens explicitly and is only used to show memory usage to the user. */
get_mem(struct module_env * env,int id)11125039b37SCy Schubert EXPORT size_t get_mem(struct module_env* env, int id) {
11225039b37SCy Schubert log_info("dynlib: hello world from get_mem");
11325039b37SCy Schubert return 0;
11425039b37SCy Schubert }
11525039b37SCy Schubert
11625039b37SCy Schubert /* The callback that was forward declared earlier. It is registered in the init
11725039b37SCy Schubert * 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)11825039b37SCy Schubert int reply_callback(struct query_info* qinfo,
11925039b37SCy Schubert struct module_qstate* qstate, struct reply_info* rep, int rcode,
12025039b37SCy Schubert struct edns_data* edns, struct edns_option** opt_list_out,
121*f44e67d1SCy Schubert struct comm_reply* repinfo, struct regional* region,
122*f44e67d1SCy Schubert struct timeval* start_time, int id, void* callback) {
12325039b37SCy Schubert log_info("dynlib: hello world from callback");
12425039b37SCy Schubert struct dynlibmod_env* env = qstate->env->modinfo[id];
12525039b37SCy Schubert if (env->dyn_env != NULL) {
12625039b37SCy Schubert log_info("dynlib: numbers gotten from query: %d, %d, and %d",
12725039b37SCy Schubert ((int *)env->dyn_env)[0],
12825039b37SCy Schubert ((int *)env->dyn_env)[1],
12925039b37SCy Schubert ((int *)env->dyn_env)[2]);
13025039b37SCy Schubert }
13125039b37SCy Schubert return 0;
13225039b37SCy Schubert }
133