modstack.c revision 307729
1331722Seadler/*
2256694Snp * services/modstack.c - stack of modules
3256694Snp *
4256694Snp * Copyright (c) 2007, NLnet Labs. All rights reserved.
5256694Snp *
6256694Snp * This software is open source.
7256694Snp *
8256694Snp * Redistribution and use in source and binary forms, with or without
9256694Snp * modification, are permitted provided that the following conditions
10256694Snp * are met:
11256694Snp *
12256694Snp * Redistributions of source code must retain the above copyright notice,
13256694Snp * this list of conditions and the following disclaimer.
14256694Snp *
15256694Snp * Redistributions in binary form must reproduce the above copyright notice,
16256694Snp * this list of conditions and the following disclaimer in the documentation
17256694Snp * and/or other materials provided with the distribution.
18256694Snp *
19256694Snp * Neither the name of the NLNET LABS nor the names of its contributors may
20256694Snp * be used to endorse or promote products derived from this software without
21256694Snp * specific prior written permission.
22256694Snp *
23256694Snp * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24256694Snp * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25256694Snp * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26256694Snp * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27256694Snp * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28256694Snp * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29256694Snp * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30256694Snp * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31256694Snp * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32256694Snp * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33256694Snp * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34256694Snp */
35256694Snp
36256694Snp/**
37256694Snp * \file
38256694Snp *
39256694Snp * This file contains functions to help maintain a stack of modules.
40256694Snp */
41256694Snp#include "config.h"
42256694Snp#include <ctype.h>
43256694Snp#include "services/modstack.h"
44256694Snp#include "util/module.h"
45256694Snp#include "util/fptr_wlist.h"
46256694Snp#include "dns64/dns64.h"
47256694Snp#include "iterator/iterator.h"
48256694Snp#include "validator/validator.h"
49256694Snp
50256694Snp#ifdef WITH_PYTHONMODULE
51256694Snp#include "pythonmod/pythonmod.h"
52256694Snp#endif
53256694Snp#ifdef USE_CACHEDB
54256694Snp#include "cachedb/cachedb.h"
55256694Snp#endif
56256694Snp
57256694Snp/** count number of modules (words) in the string */
58256694Snpstatic int
59256694Snpcount_modules(const char* s)
60256694Snp{
61256694Snp        int num = 0;
62256694Snp        if(!s)
63256694Snp                return 0;
64256694Snp        while(*s) {
65256694Snp                /* skip whitespace */
66256694Snp                while(*s && isspace((unsigned char)*s))
67256694Snp                        s++;
68256694Snp                if(*s && !isspace((unsigned char)*s)) {
69256694Snp                        /* skip identifier */
70256694Snp                        num++;
71256694Snp                        while(*s && !isspace((unsigned char)*s))
72256694Snp                                s++;
73256694Snp                }
74256694Snp        }
75256694Snp        return num;
76256694Snp}
77256694Snp
78256694Snpvoid
79256694Snpmodstack_init(struct module_stack* stack)
80256694Snp{
81256694Snp	stack->num = 0;
82256694Snp	stack->mod = NULL;
83256694Snp}
84256694Snp
85256694Snpint
86256694Snpmodstack_config(struct module_stack* stack, const char* module_conf)
87256694Snp{
88256694Snp        int i;
89256694Snp        verbose(VERB_QUERY, "module config: \"%s\"", module_conf);
90256694Snp        stack->num = count_modules(module_conf);
91256694Snp        if(stack->num == 0) {
92256694Snp                log_err("error: no modules specified");
93256694Snp                return 0;
94256694Snp        }
95256694Snp        if(stack->num > MAX_MODULE) {
96256694Snp                log_err("error: too many modules (%d max %d)",
97256694Snp                        stack->num, MAX_MODULE);
98256694Snp                return 0;
99256694Snp        }
100256694Snp        stack->mod = (struct module_func_block**)calloc((size_t)
101256694Snp                stack->num, sizeof(struct module_func_block*));
102256694Snp        if(!stack->mod) {
103256694Snp                log_err("out of memory");
104256694Snp                return 0;
105256694Snp        }
106256694Snp        for(i=0; i<stack->num; i++) {
107256694Snp                stack->mod[i] = module_factory(&module_conf);
108256694Snp                if(!stack->mod[i]) {
109256694Snp                        log_err("Unknown value for next module: '%s'",
110256694Snp                                module_conf);
111256694Snp                        return 0;
112256694Snp                }
113256694Snp        }
114256694Snp        return 1;
115256694Snp}
116256694Snp
117256694Snp/** The list of module names */
118256694Snpconst char**
119module_list_avail(void)
120{
121        /* these are the modules available */
122        static const char* names[] = {
123		"dns64",
124#ifdef WITH_PYTHONMODULE
125		"python",
126#endif
127#ifdef USE_CACHEDB
128		"cachedb",
129#endif
130		"validator",
131		"iterator",
132		NULL};
133	return names;
134}
135
136/** func block get function type */
137typedef struct module_func_block* (*fbgetfunctype)(void);
138
139/** The list of module func blocks */
140static fbgetfunctype*
141module_funcs_avail(void)
142{
143        static struct module_func_block* (*fb[])(void) = {
144		&dns64_get_funcblock,
145#ifdef WITH_PYTHONMODULE
146		&pythonmod_get_funcblock,
147#endif
148#ifdef USE_CACHEDB
149		&cachedb_get_funcblock,
150#endif
151		&val_get_funcblock,
152		&iter_get_funcblock,
153		NULL};
154	return fb;
155}
156
157struct
158module_func_block* module_factory(const char** str)
159{
160        int i = 0;
161        const char* s = *str;
162	const char** names = module_list_avail();
163	fbgetfunctype* fb = module_funcs_avail();
164        while(*s && isspace((unsigned char)*s))
165                s++;
166	while(names[i]) {
167                if(strncmp(names[i], s, strlen(names[i])) == 0) {
168                        s += strlen(names[i]);
169                        *str = s;
170                        return (*fb[i])();
171                }
172		i++;
173        }
174        return NULL;
175}
176
177int
178modstack_setup(struct module_stack* stack, const char* module_conf,
179	struct module_env* env)
180{
181        int i;
182        if(stack->num != 0)
183                modstack_desetup(stack, env);
184        /* fixed setup of the modules */
185        if(!modstack_config(stack, module_conf)) {
186		return 0;
187        }
188        env->need_to_validate = 0; /* set by module init below */
189        for(i=0; i<stack->num; i++) {
190                verbose(VERB_OPS, "init module %d: %s",
191                        i, stack->mod[i]->name);
192                fptr_ok(fptr_whitelist_mod_init(stack->mod[i]->init));
193                if(!(*stack->mod[i]->init)(env, i)) {
194                        log_err("module init for module %s failed",
195                                stack->mod[i]->name);
196			return 0;
197                }
198        }
199	return 1;
200}
201
202void
203modstack_desetup(struct module_stack* stack, struct module_env* env)
204{
205        int i;
206        for(i=0; i<stack->num; i++) {
207                fptr_ok(fptr_whitelist_mod_deinit(stack->mod[i]->deinit));
208                (*stack->mod[i]->deinit)(env, i);
209        }
210        stack->num = 0;
211        free(stack->mod);
212        stack->mod = NULL;
213}
214
215int
216modstack_find(struct module_stack* stack, const char* name)
217{
218	int i;
219        for(i=0; i<stack->num; i++) {
220		if(strcmp(stack->mod[i]->name, name) == 0)
221			return i;
222	}
223	return -1;
224}
225