xref: /lighttpd1.4/src/plugin.c (revision 6516c5a2)
18abd06a7SGlenn Strauss #include "first.h"
28abd06a7SGlenn Strauss 
396557115SGlenn Strauss #include "plugins.h"
422e8b456SStefan Bühler #include "plugin.h"
504d76e7aSGlenn Strauss #include "base.h"
6f24e6d69SGlenn Strauss #include "array.h"
722e8b456SStefan Bühler #include "log.h"
822e8b456SStefan Bühler 
9bcdc6a3bSJan Kneschke #include <string.h>
10bcdc6a3bSJan Kneschke #include <stdlib.h>
11bcdc6a3bSJan Kneschke 
12bcdc6a3bSJan Kneschke #ifdef HAVE_VALGRIND_VALGRIND_H
13bcdc6a3bSJan Kneschke # include <valgrind/valgrind.h>
14bcdc6a3bSJan Kneschke #endif
15bcdc6a3bSJan Kneschke 
16cd738d4dSGlenn Strauss #ifndef LIGHTTPD_STATIC
17cd738d4dSGlenn Strauss #ifdef HAVE_DLFCN_H
18bcdc6a3bSJan Kneschke #include <dlfcn.h>
19bcdc6a3bSJan Kneschke #endif
20cd738d4dSGlenn Strauss #endif
21bcdc6a3bSJan Kneschke /*
22bcdc6a3bSJan Kneschke  *
23bcdc6a3bSJan Kneschke  * if you change this enum to add a new callback, be sure
24bcdc6a3bSJan Kneschke  * - that PLUGIN_FUNC_SIZEOF is the last entry
25c0222695SGlenn Strauss  * - that you add:
26c0222695SGlenn Strauss  *   1. PLUGIN_CALL_... as callback-dispatcher
27c0222695SGlenn Strauss  *   2. count and assignment in plugins_call_init()
28bcdc6a3bSJan Kneschke  *
29bcdc6a3bSJan Kneschke  */
30bcdc6a3bSJan Kneschke 
31bcdc6a3bSJan Kneschke typedef enum {
32bcdc6a3bSJan Kneschke 	PLUGIN_FUNC_HANDLE_URI_CLEAN,
337b0bc129SGlenn Strauss 	PLUGIN_FUNC_HANDLE_DOCROOT,
347b0bc129SGlenn Strauss 	PLUGIN_FUNC_HANDLE_PHYSICAL,
357b0bc129SGlenn Strauss 	PLUGIN_FUNC_HANDLE_SUBREQUEST_START,
367b0bc129SGlenn Strauss 	/* PLUGIN_FUNC_HANDLE_SUBREQUEST, *//* max one handler_module per req */
377b0bc129SGlenn Strauss 	PLUGIN_FUNC_HANDLE_RESPONSE_START,
38bcdc6a3bSJan Kneschke 	PLUGIN_FUNC_HANDLE_REQUEST_DONE,
397b0bc129SGlenn Strauss 	PLUGIN_FUNC_HANDLE_REQUEST_RESET,
407b0bc129SGlenn Strauss 	PLUGIN_FUNC_HANDLE_REQUEST_ENV,
41cb7ed136SGlenn Strauss 	PLUGIN_FUNC_HANDLE_CONNECTION_ACCEPT,
42cb7ed136SGlenn Strauss 	PLUGIN_FUNC_HANDLE_CONNECTION_SHUT_WR,
43bcdc6a3bSJan Kneschke 	PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE,
44bcdc6a3bSJan Kneschke 	PLUGIN_FUNC_HANDLE_TRIGGER,
459030cfaeSGlenn Strauss 	PLUGIN_FUNC_HANDLE_WAITPID,
467b0bc129SGlenn Strauss 	PLUGIN_FUNC_HANDLE_SIGHUP,
47b73949e0SGlenn Strauss 	/* PLUGIN_FUNC_INIT, *//* handled here in plugin.c */
48b73949e0SGlenn Strauss 	/* PLUGIN_FUNC_CLEANUP, *//* handled here in plugin.c */
49bcdc6a3bSJan Kneschke 	PLUGIN_FUNC_SET_DEFAULTS,
50f1e9bcb0SGlenn Strauss 	PLUGIN_FUNC_WORKER_INIT,
51bcdc6a3bSJan Kneschke 
52bcdc6a3bSJan Kneschke 	PLUGIN_FUNC_SIZEOF
53bcdc6a3bSJan Kneschke } plugin_t;
54bcdc6a3bSJan Kneschke 
55b38817b6SGlenn Strauss __attribute_malloc__
56b38817b6SGlenn Strauss __attribute_returns_nonnull__
plugin_init(void)57bcdc6a3bSJan Kneschke static plugin *plugin_init(void) {
585e14db43SGlenn Strauss 	return ck_calloc(1, sizeof(plugin));
59bcdc6a3bSJan Kneschke }
60bcdc6a3bSJan Kneschke 
plugin_free(plugin * p)61bcdc6a3bSJan Kneschke static void plugin_free(plugin *p) {
6228f1867cSGlenn Strauss     if (NULL == p) return; /*(should not happen w/ current usage)*/
63b66fa2cbSStefan Bühler   #if !defined(LIGHTTPD_STATIC)
64e2de4e58SGlenn Strauss     if (p->lib) {
65e2de4e58SGlenn Strauss      #if defined(HAVE_VALGRIND_VALGRIND_H)
66e2de4e58SGlenn Strauss      /*if (!RUNNING_ON_VALGRIND) */
67b66fa2cbSStefan Bühler      #endif
68f49b2d74SGlenn Strauss       #ifdef _WIN32
69e2de4e58SGlenn Strauss         FreeLibrary(p->lib);
70bcdc6a3bSJan Kneschke       #else
71bcdc6a3bSJan Kneschke         dlclose(p->lib);
72bcdc6a3bSJan Kneschke       #endif
73bcdc6a3bSJan Kneschke     }
744c91a14cSJan Kneschke   #endif
75bcdc6a3bSJan Kneschke 
76bcdc6a3bSJan Kneschke     free(p);
77bcdc6a3bSJan Kneschke }
78bcdc6a3bSJan Kneschke 
79f49b2d74SGlenn Strauss #ifdef _WIN32
80f49b2d74SGlenn Strauss __attribute_cold__
81f49b2d74SGlenn Strauss static void
log_w32_syserror_2(log_error_st * const errh,const char * file,const int line,const char * const str1,const char * const str2)82f49b2d74SGlenn Strauss log_w32_syserror_2 (log_error_st *const errh, const char *file, const int line, const char * const str1, const char * const str2)
83f49b2d74SGlenn Strauss {
84f49b2d74SGlenn Strauss     TCHAR lpMsgBuf[1024];
85f49b2d74SGlenn Strauss     FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
86f49b2d74SGlenn Strauss                   0, /* MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) */
87f49b2d74SGlenn Strauss                   (LPTSTR)lpMsgBuf, sizeof(lpMsgBuf)/sizeof(TCHAR), NULL);
88f49b2d74SGlenn Strauss     log_error(errh, file, line, "%s for %s: %s", str1, str2, (char *)lpMsgBuf);
89f49b2d74SGlenn Strauss }
90f49b2d74SGlenn Strauss #endif
91f49b2d74SGlenn Strauss 
92bcdc6a3bSJan Kneschke /**
93bcdc6a3bSJan Kneschke  *
94bcdc6a3bSJan Kneschke  *
95bcdc6a3bSJan Kneschke  *
96bcdc6a3bSJan Kneschke  */
97bcdc6a3bSJan Kneschke 
98b66fa2cbSStefan Bühler #if defined(LIGHTTPD_STATIC)
99b66fa2cbSStefan Bühler 
100b66fa2cbSStefan Bühler /* pre-declare functions, as there is no header for them */
1014c91a14cSJan Kneschke #define PLUGIN_INIT(x)\
102b66fa2cbSStefan Bühler 	int x ## _plugin_init(plugin *p);
103bcdc6a3bSJan Kneschke 
104a5e280fdSJan Kneschke #include "plugin-static.h"
1054c91a14cSJan Kneschke 
106b66fa2cbSStefan Bühler #undef PLUGIN_INIT
107b66fa2cbSStefan Bühler 
108b66fa2cbSStefan Bühler /* build NULL-terminated table of name + init-function */
109b66fa2cbSStefan Bühler 
110b66fa2cbSStefan Bühler typedef struct {
111b66fa2cbSStefan Bühler 	const char* name;
112b66fa2cbSStefan Bühler 	int (*plugin_init)(plugin *p);
113b66fa2cbSStefan Bühler } plugin_load_functions;
114b66fa2cbSStefan Bühler 
115b66fa2cbSStefan Bühler static const plugin_load_functions load_functions[] = {
116b66fa2cbSStefan Bühler #define PLUGIN_INIT(x) \
117b66fa2cbSStefan Bühler 	{ #x, &x ## _plugin_init },
118b66fa2cbSStefan Bühler 
119b66fa2cbSStefan Bühler #include "plugin-static.h"
120b66fa2cbSStefan Bühler 
121b66fa2cbSStefan Bühler 	{ NULL, NULL }
122b66fa2cbSStefan Bühler #undef PLUGIN_INIT
123b66fa2cbSStefan Bühler };
124b66fa2cbSStefan Bühler 
plugins_load(server * srv)125b66fa2cbSStefan Bühler int plugins_load(server *srv) {
126c412bb59SGlenn Strauss 	ck_realloc_u32(&srv->plugins.ptr, 0,
127c412bb59SGlenn Strauss 	               srv->srvconf.modules->used, sizeof(plugin *));
128c412bb59SGlenn Strauss 
129010c2894SGlenn Strauss 	for (uint32_t i = 0; i < srv->srvconf.modules->used; ++i) {
130601c572cSGlenn Strauss 		data_string *ds = (data_string *)srv->srvconf.modules->data[i];
131601c572cSGlenn Strauss 		char *module = ds->value.ptr;
132b66fa2cbSStefan Bühler 
133010c2894SGlenn Strauss 		uint32_t j;
134b66fa2cbSStefan Bühler 		for (j = 0; load_functions[j].name; ++j) {
135b66fa2cbSStefan Bühler 			if (0 == strcmp(load_functions[j].name, module)) {
136010c2894SGlenn Strauss 				plugin * const p = plugin_init();
137b66fa2cbSStefan Bühler 				if ((*load_functions[j].plugin_init)(p)) {
138010c2894SGlenn Strauss 					log_error(srv->errh, __FILE__, __LINE__, "%s plugin init failed", module);
139b66fa2cbSStefan Bühler 					plugin_free(p);
140b66fa2cbSStefan Bühler 					return -1;
141b66fa2cbSStefan Bühler 				}
142c412bb59SGlenn Strauss 				((plugin **)srv->plugins.ptr)[srv->plugins.used++] = p;
143b66fa2cbSStefan Bühler 				break;
144b66fa2cbSStefan Bühler 			}
145b66fa2cbSStefan Bühler 		}
146b66fa2cbSStefan Bühler 		if (!load_functions[j].name) {
147010c2894SGlenn Strauss 			log_error(srv->errh, __FILE__, __LINE__, "%s plugin not found", module);
14807523015SGlenn Strauss 			if (srv->srvconf.compat_module_load) {
14907523015SGlenn Strauss 				if (buffer_eq_slen(&ds->value, CONST_STR_LEN("mod_deflate")))
15007523015SGlenn Strauss 					continue;
15107523015SGlenn Strauss 			}
152b66fa2cbSStefan Bühler 			return -1;
153b66fa2cbSStefan Bühler 		}
154b66fa2cbSStefan Bühler 	}
155b66fa2cbSStefan Bühler 
1564c91a14cSJan Kneschke 	return 0;
1574c91a14cSJan Kneschke }
158f49b2d74SGlenn Strauss 
159b66fa2cbSStefan Bühler #else /* defined(LIGHTTPD_STATIC) */
160f49b2d74SGlenn Strauss 
plugins_load(server * srv)161bcdc6a3bSJan Kneschke int plugins_load(server *srv) {
162c412bb59SGlenn Strauss 	ck_realloc_u32(&srv->plugins.ptr, 0,
163c412bb59SGlenn Strauss 	               srv->srvconf.modules->used, sizeof(plugin *));
164c412bb59SGlenn Strauss 
165ca97505aSGlenn Strauss 	buffer * const tb = srv->tmp_buf;
166bcdc6a3bSJan Kneschke 	int (*init)(plugin *pl);
167bcdc6a3bSJan Kneschke 
16878ec2b5bSGlenn Strauss 	for (uint32_t i = 0; i < srv->srvconf.modules->used; ++i) {
16978ec2b5bSGlenn Strauss 		const buffer * const module = &((data_string *)srv->srvconf.modules->data[i])->value;
170f49b2d74SGlenn Strauss 		void *lib = NULL;
171f49b2d74SGlenn Strauss 
1723bc7866fSGlenn Strauss 		/* check if module is built-in to main executable */
1733bc7866fSGlenn Strauss 		buffer_clear(tb);
1743bc7866fSGlenn Strauss 		buffer_append_str2(tb, BUF_PTR_LEN(module),
1753bc7866fSGlenn Strauss 		                       CONST_STR_LEN("_plugin_init"));
1763bc7866fSGlenn Strauss 	  #ifdef _WIN32
1773bc7866fSGlenn Strauss 		init = (int(WINAPI *)(plugin *))(intptr_t)
1783bc7866fSGlenn Strauss 		  GetProcAddress(GetModuleHandle(NULL), tb->ptr);
1793bc7866fSGlenn Strauss 	  #else
1803bc7866fSGlenn Strauss 		init = (int (*)(plugin *))(intptr_t)dlsym(RTLD_DEFAULT, tb->ptr);
1813bc7866fSGlenn Strauss 	  #endif
1823bc7866fSGlenn Strauss 
1833bc7866fSGlenn Strauss 	  if (NULL == init) {
18410b307bdSGlenn Strauss 		buffer_copy_string(tb, srv->srvconf.modules_dir);
18510b307bdSGlenn Strauss 		buffer_append_path_len(tb, BUF_PTR_LEN(module));
186f49b2d74SGlenn Strauss 
187f49b2d74SGlenn Strauss 	  #ifdef _WIN32
188f49b2d74SGlenn Strauss 		buffer_append_string_len(tb, CONST_STR_LEN(".dll"));
189f49b2d74SGlenn Strauss 		if (NULL == (lib = LoadLibrary(tb->ptr))) {
190f49b2d74SGlenn Strauss 			log_w32_syserror_2(srv->errh, __FILE__, __LINE__,
191f49b2d74SGlenn Strauss 			                   "LoadLibrary()", tb->ptr);
192f49b2d74SGlenn Strauss 			if (srv->srvconf.compat_module_load) {
193f49b2d74SGlenn Strauss 				if (buffer_eq_slen(module, CONST_STR_LEN("mod_deflate")))
194f49b2d74SGlenn Strauss 					continue;
195f49b2d74SGlenn Strauss 			}
196f49b2d74SGlenn Strauss 			return -1;
197f49b2d74SGlenn Strauss 		}
198f49b2d74SGlenn Strauss 		buffer_copy_buffer(tb, module);
199f49b2d74SGlenn Strauss 		buffer_append_string_len(tb, CONST_STR_LEN("_plugin_init"));
200f49b2d74SGlenn Strauss 		init = (int(WINAPI *)(plugin *))(intptr_t)GetProcAddress(lib, tb->ptr);
201f49b2d74SGlenn Strauss 		if (init == NULL) {
202f49b2d74SGlenn Strauss 			log_w32_syserror_2(srv->errh, __FILE__, __LINE__,
203f49b2d74SGlenn Strauss 			                   "GetProcAddress()", tb->ptr);
204f49b2d74SGlenn Strauss 		        FreeLibrary(lib);
205f49b2d74SGlenn Strauss 			return -1;
206f49b2d74SGlenn Strauss 		}
207f49b2d74SGlenn Strauss 	  #else
208f49b2d74SGlenn Strauss 	   #if defined(__CYGWIN__)
209ca97505aSGlenn Strauss 		buffer_append_string_len(tb, CONST_STR_LEN(".dll"));
210bcdc6a3bSJan Kneschke 	   #else
211ca97505aSGlenn Strauss 		buffer_append_string_len(tb, CONST_STR_LEN(".so"));
212bcdc6a3bSJan Kneschke 	   #endif
213f49b2d74SGlenn Strauss 		if (NULL == (lib = dlopen(tb->ptr, RTLD_NOW|RTLD_GLOBAL))) {
214010c2894SGlenn Strauss 			log_error(srv->errh, __FILE__, __LINE__,
215ca97505aSGlenn Strauss 			  "dlopen() failed for: %s %s", tb->ptr, dlerror());
21607523015SGlenn Strauss 			if (srv->srvconf.compat_module_load) {
21707523015SGlenn Strauss 				if (buffer_eq_slen(module, CONST_STR_LEN("mod_deflate")))
21807523015SGlenn Strauss 					continue;
21907523015SGlenn Strauss 			}
220bcdc6a3bSJan Kneschke 			return -1;
221bcdc6a3bSJan Kneschke 		}
222dc01487eSGlenn Strauss 		buffer_clear(tb);
223af3df29aSGlenn Strauss 		buffer_append_str2(tb, BUF_PTR_LEN(module),
224dc01487eSGlenn Strauss                                        CONST_STR_LEN("_plugin_init"));
225f49b2d74SGlenn Strauss 		init = (int (*)(plugin *))(intptr_t)dlsym(lib, tb->ptr);
226eefb94bbSGlenn Strauss 		if (NULL == init) {
227eefb94bbSGlenn Strauss 			const char *error = dlerror();
228eefb94bbSGlenn Strauss 			if (error != NULL) {
229010c2894SGlenn Strauss 				log_error(srv->errh, __FILE__, __LINE__, "dlsym: %s", error);
230eefb94bbSGlenn Strauss 			} else {
231ca97505aSGlenn Strauss 				log_error(srv->errh, __FILE__, __LINE__, "dlsym symbol not found: %s", tb->ptr);
232eefb94bbSGlenn Strauss 			}
233f49b2d74SGlenn Strauss 		        dlclose(lib);
234bcdc6a3bSJan Kneschke 			return -1;
235bcdc6a3bSJan Kneschke 		}
236bcdc6a3bSJan Kneschke 	  #endif
2373bc7866fSGlenn Strauss 	  }
238f49b2d74SGlenn Strauss 
239f49b2d74SGlenn Strauss 		plugin *p = plugin_init();
240f49b2d74SGlenn Strauss 		p->lib = lib;
241bcdc6a3bSJan Kneschke 		if ((*init)(p)) {
24278ec2b5bSGlenn Strauss 			log_error(srv->errh, __FILE__, __LINE__, "%s plugin init failed", module->ptr);
243bcdc6a3bSJan Kneschke 			plugin_free(p);
244bcdc6a3bSJan Kneschke 			return -1;
245bcdc6a3bSJan Kneschke 		}
246c412bb59SGlenn Strauss 		((plugin **)srv->plugins.ptr)[srv->plugins.used++] = p;
247bcdc6a3bSJan Kneschke 	}
248bcdc6a3bSJan Kneschke 
249bcdc6a3bSJan Kneschke 	return 0;
250bcdc6a3bSJan Kneschke }
251f49b2d74SGlenn Strauss 
252b66fa2cbSStefan Bühler #endif /* defined(LIGHTTPD_STATIC) */
253bcdc6a3bSJan Kneschke 
254*6516c5a2SGlenn Strauss typedef handler_t(*pl_cb_t)(void *, void *);
255*6516c5a2SGlenn Strauss 
256*6516c5a2SGlenn Strauss /*(alternative to multiple structs would be union for fn ptr type)*/
257*6516c5a2SGlenn Strauss 
258c0222695SGlenn Strauss typedef struct {
259*6516c5a2SGlenn Strauss   pl_cb_t fn;
260b2b41e36SGlenn Strauss   plugin_data_base *data;
261c0222695SGlenn Strauss } plugin_fn_data;
262c0222695SGlenn Strauss 
263*6516c5a2SGlenn Strauss typedef struct {
264*6516c5a2SGlenn Strauss   handler_t(*fn)(request_st *, void *);
265*6516c5a2SGlenn Strauss   plugin_data_base *data;
266*6516c5a2SGlenn Strauss } plugin_fn_req_data;
267*6516c5a2SGlenn Strauss 
268*6516c5a2SGlenn Strauss typedef struct {
269*6516c5a2SGlenn Strauss   handler_t(*fn)(connection *, void *);
270*6516c5a2SGlenn Strauss   plugin_data_base *data;
271*6516c5a2SGlenn Strauss } plugin_fn_con_data;
272*6516c5a2SGlenn Strauss 
273*6516c5a2SGlenn Strauss typedef struct {
274*6516c5a2SGlenn Strauss   handler_t(*fn)(server *, void *);
275*6516c5a2SGlenn Strauss   plugin_data_base *data;
276*6516c5a2SGlenn Strauss } plugin_fn_srv_data;
277*6516c5a2SGlenn Strauss 
278*6516c5a2SGlenn Strauss typedef struct {
279*6516c5a2SGlenn Strauss   handler_t(*fn)(server *, void *, pid_t, int);
280*6516c5a2SGlenn Strauss   plugin_data_base *data;
281*6516c5a2SGlenn Strauss } plugin_fn_waitpid_data;
282*6516c5a2SGlenn Strauss 
283c0222695SGlenn Strauss __attribute_hot__
plugins_call_fn_req_data(request_st * const r,const int e)2847c7f8c46SGlenn Strauss static handler_t plugins_call_fn_req_data(request_st * const r, const int e) {
2857c7f8c46SGlenn Strauss     const void * const plugin_slots = r->con->plugin_slots;
2867c7f8c46SGlenn Strauss     const uint32_t offset = ((const uint16_t *)plugin_slots)[e];
2877c7f8c46SGlenn Strauss     if (0 == offset) return HANDLER_GO_ON;
288*6516c5a2SGlenn Strauss     const plugin_fn_req_data *plfd = (const plugin_fn_req_data *)
2897c7f8c46SGlenn Strauss       (((uintptr_t)plugin_slots) + offset);
2907c7f8c46SGlenn Strauss     handler_t rc = HANDLER_GO_ON;
2917c7f8c46SGlenn Strauss     while (plfd->fn && (rc = plfd->fn(r, plfd->data)) == HANDLER_GO_ON)
2927c7f8c46SGlenn Strauss         ++plfd;
2937c7f8c46SGlenn Strauss     return rc;
2947c7f8c46SGlenn Strauss }
2957c7f8c46SGlenn Strauss 
2967c7f8c46SGlenn Strauss __attribute_hot__
plugins_call_fn_con_data(connection * const con,const int e)29750bdb55dSGlenn Strauss static handler_t plugins_call_fn_con_data(connection * const con, const int e) {
29850bdb55dSGlenn Strauss     const void * const plugin_slots = con->plugin_slots;
29950bdb55dSGlenn Strauss     const uint32_t offset = ((const uint16_t *)plugin_slots)[e];
300c0222695SGlenn Strauss     if (0 == offset) return HANDLER_GO_ON;
301*6516c5a2SGlenn Strauss     const plugin_fn_con_data *plfd = (const plugin_fn_con_data *)
30250bdb55dSGlenn Strauss       (((uintptr_t)plugin_slots) + offset);
303c0222695SGlenn Strauss     handler_t rc = HANDLER_GO_ON;
30450bdb55dSGlenn Strauss     while (plfd->fn && (rc = plfd->fn(con, plfd->data)) == HANDLER_GO_ON)
305c0222695SGlenn Strauss         ++plfd;
306c0222695SGlenn Strauss     return rc;
307c0222695SGlenn Strauss }
308c0222695SGlenn Strauss 
plugins_call_fn_srv_data(server * const srv,const int e)309c0222695SGlenn Strauss static handler_t plugins_call_fn_srv_data(server * const srv, const int e) {
310c0222695SGlenn Strauss     const uint32_t offset = ((const uint16_t *)srv->plugin_slots)[e];
311c0222695SGlenn Strauss     if (0 == offset) return HANDLER_GO_ON;
312*6516c5a2SGlenn Strauss     const plugin_fn_srv_data *plfd = (const plugin_fn_srv_data *)
313c0222695SGlenn Strauss       (((uintptr_t)srv->plugin_slots) + offset);
314c0222695SGlenn Strauss     handler_t rc = HANDLER_GO_ON;
315c0222695SGlenn Strauss     while (plfd->fn && (rc = plfd->fn(srv,plfd->data)) == HANDLER_GO_ON)
316c0222695SGlenn Strauss         ++plfd;
317c0222695SGlenn Strauss     return rc;
318bcdc6a3bSJan Kneschke }
319bcdc6a3bSJan Kneschke 
plugins_call_fn_srv_data_all(server * const srv,const int e)320ba88ff0eSGlenn Strauss static void plugins_call_fn_srv_data_all(server * const srv, const int e) {
321ba88ff0eSGlenn Strauss     const uint32_t offset = ((const uint16_t *)srv->plugin_slots)[e];
322ba88ff0eSGlenn Strauss     if (0 == offset) return;
323*6516c5a2SGlenn Strauss     const plugin_fn_srv_data *plfd = (const plugin_fn_srv_data *)
324ba88ff0eSGlenn Strauss       (((uintptr_t)srv->plugin_slots) + offset);
325ba88ff0eSGlenn Strauss     for (; plfd->fn; ++plfd)
326ba88ff0eSGlenn Strauss         plfd->fn(srv, plfd->data);
327ba88ff0eSGlenn Strauss }
328ba88ff0eSGlenn Strauss 
329bcdc6a3bSJan Kneschke /**
330bcdc6a3bSJan Kneschke  * plugins that use
331bcdc6a3bSJan Kneschke  *
3327c7f8c46SGlenn Strauss  * - request_st *r
3337c7f8c46SGlenn Strauss  * - void *p_d (plugin_data *)
3347c7f8c46SGlenn Strauss  */
3357c7f8c46SGlenn Strauss 
3367c7f8c46SGlenn Strauss #define PLUGIN_CALL_FN_REQ_DATA(x, y) \
3377c7f8c46SGlenn Strauss     handler_t plugins_call_##y(request_st * const r) {\
3387c7f8c46SGlenn Strauss         return plugins_call_fn_req_data(r, x); \
3397c7f8c46SGlenn Strauss     }
3407c7f8c46SGlenn Strauss 
PLUGIN_CALL_FN_REQ_DATA(PLUGIN_FUNC_HANDLE_URI_CLEAN,handle_uri_clean)3417c7f8c46SGlenn Strauss PLUGIN_CALL_FN_REQ_DATA(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean)
3427c7f8c46SGlenn Strauss PLUGIN_CALL_FN_REQ_DATA(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot)
3437c7f8c46SGlenn Strauss PLUGIN_CALL_FN_REQ_DATA(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical)
3447b0bc129SGlenn Strauss PLUGIN_CALL_FN_REQ_DATA(PLUGIN_FUNC_HANDLE_SUBREQUEST_START, handle_subrequest_start)
3457b0bc129SGlenn Strauss PLUGIN_CALL_FN_REQ_DATA(PLUGIN_FUNC_HANDLE_RESPONSE_START, handle_response_start)
3467b0bc129SGlenn Strauss PLUGIN_CALL_FN_REQ_DATA(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done)
3477b0bc129SGlenn Strauss PLUGIN_CALL_FN_REQ_DATA(PLUGIN_FUNC_HANDLE_REQUEST_RESET, handle_request_reset)
3487b0bc129SGlenn Strauss PLUGIN_CALL_FN_REQ_DATA(PLUGIN_FUNC_HANDLE_REQUEST_ENV, handle_request_env)
3497c7f8c46SGlenn Strauss 
3507c7f8c46SGlenn Strauss /**
3517c7f8c46SGlenn Strauss  * plugins that use
3527c7f8c46SGlenn Strauss  *
353bcdc6a3bSJan Kneschke  * - connection *con
354bcdc6a3bSJan Kneschke  * - void *p_d (plugin_data *)
355bcdc6a3bSJan Kneschke  */
356bcdc6a3bSJan Kneschke 
35750bdb55dSGlenn Strauss #define PLUGIN_CALL_FN_CON_DATA(x, y) \
35850bdb55dSGlenn Strauss     handler_t plugins_call_##y(connection *con) {\
35950bdb55dSGlenn Strauss         return plugins_call_fn_con_data(con, x); \
360bcdc6a3bSJan Kneschke     }
361bcdc6a3bSJan Kneschke 
36250bdb55dSGlenn Strauss PLUGIN_CALL_FN_CON_DATA(PLUGIN_FUNC_HANDLE_CONNECTION_ACCEPT, handle_connection_accept)
36350bdb55dSGlenn Strauss PLUGIN_CALL_FN_CON_DATA(PLUGIN_FUNC_HANDLE_CONNECTION_SHUT_WR, handle_connection_shut_wr)
36450bdb55dSGlenn Strauss PLUGIN_CALL_FN_CON_DATA(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close)
365c0222695SGlenn Strauss 
366c0222695SGlenn Strauss #undef PLUGIN_CALL_FN_SRV_CON_DATA
367c0222695SGlenn Strauss 
368bcdc6a3bSJan Kneschke /**
369bcdc6a3bSJan Kneschke  * plugins that use
370bcdc6a3bSJan Kneschke  *
371bcdc6a3bSJan Kneschke  * - server *srv
372bcdc6a3bSJan Kneschke  * - void *p_d (plugin_data *)
373bcdc6a3bSJan Kneschke  */
374bcdc6a3bSJan Kneschke 
375ba88ff0eSGlenn Strauss handler_t plugins_call_set_defaults(server *srv) {
376ba88ff0eSGlenn Strauss     return plugins_call_fn_srv_data(srv, PLUGIN_FUNC_SET_DEFAULTS);
377c0222695SGlenn Strauss }
378bcdc6a3bSJan Kneschke 
plugins_call_worker_init(server * srv)379ba88ff0eSGlenn Strauss handler_t plugins_call_worker_init(server *srv) {
380ba88ff0eSGlenn Strauss     return plugins_call_fn_srv_data(srv, PLUGIN_FUNC_WORKER_INIT);
381ba88ff0eSGlenn Strauss }
382c0222695SGlenn Strauss 
plugins_call_handle_trigger(server * srv)383ba88ff0eSGlenn Strauss void plugins_call_handle_trigger(server *srv) {
384ba88ff0eSGlenn Strauss     plugins_call_fn_srv_data_all(srv, PLUGIN_FUNC_HANDLE_TRIGGER);
385ba88ff0eSGlenn Strauss }
386ba88ff0eSGlenn Strauss 
plugins_call_handle_sighup(server * srv)387ba88ff0eSGlenn Strauss void plugins_call_handle_sighup(server *srv) {
388ba88ff0eSGlenn Strauss     plugins_call_fn_srv_data_all(srv, PLUGIN_FUNC_HANDLE_SIGHUP);
389ba88ff0eSGlenn Strauss }
390bcdc6a3bSJan Kneschke 
plugins_call_handle_waitpid(server * srv,pid_t pid,int status)3919030cfaeSGlenn Strauss handler_t plugins_call_handle_waitpid(server *srv, pid_t pid, int status) {
392c0222695SGlenn Strauss     const uint32_t offset =
393c0222695SGlenn Strauss       ((const uint16_t *)srv->plugin_slots)[PLUGIN_FUNC_HANDLE_WAITPID];
394c0222695SGlenn Strauss     if (0 == offset) return HANDLER_GO_ON;
395*6516c5a2SGlenn Strauss     const plugin_fn_waitpid_data *plfd = (const plugin_fn_waitpid_data *)
396c0222695SGlenn Strauss       (((uintptr_t)srv->plugin_slots) + offset);
397c0222695SGlenn Strauss     handler_t rc = HANDLER_GO_ON;
398c0222695SGlenn Strauss     while (plfd->fn&&(rc=plfd->fn(srv,plfd->data,pid,status))==HANDLER_GO_ON)
399c0222695SGlenn Strauss         ++plfd;
400c0222695SGlenn Strauss     return rc;
4019030cfaeSGlenn Strauss }
4029030cfaeSGlenn Strauss 
plugins_call_cleanup(server * const srv)403b73949e0SGlenn Strauss static void plugins_call_cleanup(server * const srv) {
404b73949e0SGlenn Strauss     plugin ** const ps = srv->plugins.ptr;
405b73949e0SGlenn Strauss     for (uint32_t i = 0; i < srv->plugins.used; ++i) {
406b73949e0SGlenn Strauss         plugin *p = ps[i];
407b73949e0SGlenn Strauss         if (NULL == p) continue;
408b73949e0SGlenn Strauss         if (NULL != p->data) {
409b73949e0SGlenn Strauss             plugin_data_base *pd = p->data;
410b73949e0SGlenn Strauss             if (p->cleanup)
411b73949e0SGlenn Strauss                 p->cleanup(p->data);
412b73949e0SGlenn Strauss             free(pd->cvlist);
413b73949e0SGlenn Strauss             free(pd);
414b73949e0SGlenn Strauss             p->data = NULL;
415b73949e0SGlenn Strauss         }
416b73949e0SGlenn Strauss     }
417b73949e0SGlenn Strauss }
418b73949e0SGlenn Strauss 
4199974b57aSGlenn Strauss __attribute_cold__
plugins_call_init_reverse(server * srv,const uint32_t offset)4209974b57aSGlenn Strauss static void plugins_call_init_reverse(server *srv, const uint32_t offset) {
4219974b57aSGlenn Strauss     if (0 == offset) return;
4229974b57aSGlenn Strauss     plugin_fn_data *a = (plugin_fn_data *)
4239974b57aSGlenn Strauss       (((uintptr_t)srv->plugin_slots) + offset);
4249974b57aSGlenn Strauss     plugin_fn_data *b = a;
4259974b57aSGlenn Strauss     while (b->fn) ++b;
4269974b57aSGlenn Strauss     for (; a < --b; ++a) { /* swap to reverse list */
4279974b57aSGlenn Strauss         plugin_fn_data tmp = *a;
4289974b57aSGlenn Strauss         *a = *b;
4299974b57aSGlenn Strauss         *b = tmp;
4309974b57aSGlenn Strauss     }
4319974b57aSGlenn Strauss }
432bcdc6a3bSJan Kneschke 
433c0222695SGlenn Strauss __attribute_cold__
plugins_call_init_slot(server * srv,pl_cb_t fn,void * data,const uint32_t offset)434*6516c5a2SGlenn Strauss static void plugins_call_init_slot(server *srv, pl_cb_t fn, void *data, const uint32_t offset) {
435c0222695SGlenn Strauss     if (fn) {
436c0222695SGlenn Strauss         plugin_fn_data *plfd = (plugin_fn_data *)
437c0222695SGlenn Strauss           (((uintptr_t)srv->plugin_slots) + offset);
438c0222695SGlenn Strauss         while (plfd->fn) ++plfd;
439c0222695SGlenn Strauss         plfd->fn = fn;
440c0222695SGlenn Strauss         plfd->data = data;
441c0222695SGlenn Strauss     }
442c0222695SGlenn Strauss }
443c0222695SGlenn Strauss 
plugins_call_init(server * srv)444bcdc6a3bSJan Kneschke handler_t plugins_call_init(server *srv) {
44562e97967SGlenn Strauss 	plugin ** const ps = srv->plugins.ptr;
446c0222695SGlenn Strauss 	uint16_t offsets[PLUGIN_FUNC_SIZEOF];
447c0222695SGlenn Strauss 	memset(offsets, 0, sizeof(offsets));
448bcdc6a3bSJan Kneschke 
44962e97967SGlenn Strauss 	for (uint32_t i = 0; i < srv->plugins.used; ++i) {
450bcdc6a3bSJan Kneschke 		/* check which calls are supported */
451bcdc6a3bSJan Kneschke 
452bcdc6a3bSJan Kneschke 		plugin *p = ps[i];
453bcdc6a3bSJan Kneschke 
454bcdc6a3bSJan Kneschke 		if (p->init) {
455bcdc6a3bSJan Kneschke 			if (NULL == (p->data = p->init())) {
456010c2894SGlenn Strauss 				log_error(srv->errh, __FILE__, __LINE__,
457010c2894SGlenn Strauss 				  "plugin-init failed for module %s", p->name);
458bcdc6a3bSJan Kneschke 				return HANDLER_ERROR;
459bcdc6a3bSJan Kneschke 			}
460bcdc6a3bSJan Kneschke 
461eea7cd3cSGlenn Strauss 			((plugin_data_base *)(p->data))->self = p;
462b2b41e36SGlenn Strauss 			((plugin_data_base *)(p->data))->id = i + 1;
463bcdc6a3bSJan Kneschke 
464bcdc6a3bSJan Kneschke 			if (p->version != LIGHTTPD_VERSION_ID) {
465010c2894SGlenn Strauss 				log_error(srv->errh, __FILE__, __LINE__,
466010c2894SGlenn Strauss 				  "plugin-version doesn't match lighttpd-version for %s", p->name);
467bcdc6a3bSJan Kneschke 				return HANDLER_ERROR;
468bcdc6a3bSJan Kneschke 			}
469bcdc6a3bSJan Kneschke 		}
4708af9e71cSGlenn Strauss 
4718af9e71cSGlenn Strauss 		if (p->priv_defaults && HANDLER_ERROR==p->priv_defaults(srv, p->data)) {
4728af9e71cSGlenn Strauss 			return HANDLER_ERROR;
4738af9e71cSGlenn Strauss 		}
474c0222695SGlenn Strauss 
475c0222695SGlenn Strauss 		if (p->handle_uri_clean)
476c0222695SGlenn Strauss 			++offsets[PLUGIN_FUNC_HANDLE_URI_CLEAN];
4770afab29cSGlenn Strauss 		if (p->handle_uri_raw && !p->handle_uri_clean)
4780afab29cSGlenn Strauss 			++offsets[PLUGIN_FUNC_HANDLE_URI_CLEAN]; /*(same as above)*/
479c0222695SGlenn Strauss 		if (p->handle_request_env)
480c0222695SGlenn Strauss 			++offsets[PLUGIN_FUNC_HANDLE_REQUEST_ENV];
481c0222695SGlenn Strauss 		if (p->handle_request_done)
482c0222695SGlenn Strauss 			++offsets[PLUGIN_FUNC_HANDLE_REQUEST_DONE];
483c0222695SGlenn Strauss 		if (p->handle_connection_accept)
484c0222695SGlenn Strauss 			++offsets[PLUGIN_FUNC_HANDLE_CONNECTION_ACCEPT];
485c0222695SGlenn Strauss 		if (p->handle_connection_shut_wr)
486c0222695SGlenn Strauss 			++offsets[PLUGIN_FUNC_HANDLE_CONNECTION_SHUT_WR];
487c0222695SGlenn Strauss 		if (p->handle_connection_close)
488c0222695SGlenn Strauss 			++offsets[PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE];
489c0222695SGlenn Strauss 		if (p->handle_trigger)
490c0222695SGlenn Strauss 			++offsets[PLUGIN_FUNC_HANDLE_TRIGGER];
491c0222695SGlenn Strauss 		if (p->handle_sighup)
492c0222695SGlenn Strauss 			++offsets[PLUGIN_FUNC_HANDLE_SIGHUP];
493c0222695SGlenn Strauss 		if (p->handle_waitpid)
494c0222695SGlenn Strauss 			++offsets[PLUGIN_FUNC_HANDLE_WAITPID];
495c0222695SGlenn Strauss 		if (p->handle_subrequest_start)
496c0222695SGlenn Strauss 			++offsets[PLUGIN_FUNC_HANDLE_SUBREQUEST_START];
497c0222695SGlenn Strauss 		if (p->handle_response_start)
498c0222695SGlenn Strauss 			++offsets[PLUGIN_FUNC_HANDLE_RESPONSE_START];
499c0222695SGlenn Strauss 		if (p->handle_docroot)
500c0222695SGlenn Strauss 			++offsets[PLUGIN_FUNC_HANDLE_DOCROOT];
501c0222695SGlenn Strauss 		if (p->handle_physical)
502c0222695SGlenn Strauss 			++offsets[PLUGIN_FUNC_HANDLE_PHYSICAL];
50333c8cf41SGlenn Strauss 		if (p->handle_request_reset)
5047b0bc129SGlenn Strauss 			++offsets[PLUGIN_FUNC_HANDLE_REQUEST_RESET];
505c0222695SGlenn Strauss 		if (p->set_defaults)
506c0222695SGlenn Strauss 			++offsets[PLUGIN_FUNC_SET_DEFAULTS];
507c0222695SGlenn Strauss 		if (p->worker_init)
508c0222695SGlenn Strauss 			++offsets[PLUGIN_FUNC_WORKER_INIT];
509c0222695SGlenn Strauss 	}
510c0222695SGlenn Strauss 
511c0222695SGlenn Strauss 	uint32_t nslots =
512c0222695SGlenn Strauss 	  (sizeof(offsets)+sizeof(plugin_fn_data)-1) / sizeof(plugin_fn_data);
513c0222695SGlenn Strauss 	for (uint32_t i = 0; i < PLUGIN_FUNC_SIZEOF; ++i) {
514c0222695SGlenn Strauss 		if (offsets[i]) {
515c0222695SGlenn Strauss 			uint32_t offset = nslots;
516c0222695SGlenn Strauss 			nslots += offsets[i]+1; /* +1 to mark end of each list */
517c0222695SGlenn Strauss 			force_assert(offset * sizeof(plugin_fn_data) <= USHRT_MAX);
518c0222695SGlenn Strauss 			offsets[i] = (uint16_t)(offset * sizeof(plugin_fn_data));
519c0222695SGlenn Strauss 		}
520c0222695SGlenn Strauss 	}
521c0222695SGlenn Strauss 
522c0222695SGlenn Strauss 	/* allocate and fill slots of two dimensional array */
5235e14db43SGlenn Strauss 	srv->plugin_slots = ck_calloc(nslots, sizeof(plugin_fn_data));
524c0222695SGlenn Strauss 	memcpy(srv->plugin_slots, offsets, sizeof(offsets));
525c0222695SGlenn Strauss 
5260afab29cSGlenn Strauss 	/* add handle_uri_raw before handle_uri_clean, but in same slot */
5270afab29cSGlenn Strauss 	for (uint32_t i = 0; i < srv->plugins.used; ++i) {
5280afab29cSGlenn Strauss 		plugin * const p = ps[i];
529*6516c5a2SGlenn Strauss 		plugins_call_init_slot(srv, (pl_cb_t)p->handle_uri_raw, p->data,
5300afab29cSGlenn Strauss 					offsets[PLUGIN_FUNC_HANDLE_URI_CLEAN]);
5310afab29cSGlenn Strauss 	}
5320afab29cSGlenn Strauss 
533c0222695SGlenn Strauss 	for (uint32_t i = 0; i < srv->plugins.used; ++i) {
534c0222695SGlenn Strauss 		plugin * const p = ps[i];
535c0222695SGlenn Strauss 
5360afab29cSGlenn Strauss 		if (!p->handle_uri_raw)
537*6516c5a2SGlenn Strauss 			plugins_call_init_slot(srv, (pl_cb_t)p->handle_uri_clean, p->data,
538c0222695SGlenn Strauss 						offsets[PLUGIN_FUNC_HANDLE_URI_CLEAN]);
539*6516c5a2SGlenn Strauss 		plugins_call_init_slot(srv, (pl_cb_t)p->handle_request_env, p->data,
540c0222695SGlenn Strauss 					offsets[PLUGIN_FUNC_HANDLE_REQUEST_ENV]);
541*6516c5a2SGlenn Strauss 		plugins_call_init_slot(srv, (pl_cb_t)p->handle_request_done, p->data,
542c0222695SGlenn Strauss 					offsets[PLUGIN_FUNC_HANDLE_REQUEST_DONE]);
543*6516c5a2SGlenn Strauss 		plugins_call_init_slot(srv, (pl_cb_t)p->handle_connection_accept, p->data,
544c0222695SGlenn Strauss 					offsets[PLUGIN_FUNC_HANDLE_CONNECTION_ACCEPT]);
545*6516c5a2SGlenn Strauss 		plugins_call_init_slot(srv, (pl_cb_t)p->handle_connection_shut_wr, p->data,
546c0222695SGlenn Strauss 					offsets[PLUGIN_FUNC_HANDLE_CONNECTION_SHUT_WR]);
547*6516c5a2SGlenn Strauss 		plugins_call_init_slot(srv, (pl_cb_t)p->handle_connection_close, p->data,
548c0222695SGlenn Strauss 					offsets[PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE]);
549*6516c5a2SGlenn Strauss 		plugins_call_init_slot(srv, (pl_cb_t)p->handle_trigger, p->data,
550c0222695SGlenn Strauss 					offsets[PLUGIN_FUNC_HANDLE_TRIGGER]);
551*6516c5a2SGlenn Strauss 		plugins_call_init_slot(srv, (pl_cb_t)p->handle_sighup, p->data,
552c0222695SGlenn Strauss 					offsets[PLUGIN_FUNC_HANDLE_SIGHUP]);
553*6516c5a2SGlenn Strauss 		plugins_call_init_slot(srv, (pl_cb_t)(uintptr_t)p->handle_waitpid, p->data,
554c0222695SGlenn Strauss 					offsets[PLUGIN_FUNC_HANDLE_WAITPID]);
555*6516c5a2SGlenn Strauss 		plugins_call_init_slot(srv, (pl_cb_t)p->handle_subrequest_start, p->data,
556c0222695SGlenn Strauss 					offsets[PLUGIN_FUNC_HANDLE_SUBREQUEST_START]);
557*6516c5a2SGlenn Strauss 		plugins_call_init_slot(srv, (pl_cb_t)p->handle_response_start, p->data,
558c0222695SGlenn Strauss 					offsets[PLUGIN_FUNC_HANDLE_RESPONSE_START]);
559*6516c5a2SGlenn Strauss 		plugins_call_init_slot(srv, (pl_cb_t)p->handle_docroot, p->data,
560c0222695SGlenn Strauss 					offsets[PLUGIN_FUNC_HANDLE_DOCROOT]);
561*6516c5a2SGlenn Strauss 		plugins_call_init_slot(srv, (pl_cb_t)p->handle_physical, p->data,
562c0222695SGlenn Strauss 					offsets[PLUGIN_FUNC_HANDLE_PHYSICAL]);
563*6516c5a2SGlenn Strauss 		plugins_call_init_slot(srv, (pl_cb_t)p->handle_request_reset, p->data,
5647b0bc129SGlenn Strauss 					offsets[PLUGIN_FUNC_HANDLE_REQUEST_RESET]);
565*6516c5a2SGlenn Strauss 		plugins_call_init_slot(srv, (pl_cb_t)p->set_defaults, p->data,
566c0222695SGlenn Strauss 					offsets[PLUGIN_FUNC_SET_DEFAULTS]);
567*6516c5a2SGlenn Strauss 		plugins_call_init_slot(srv, (pl_cb_t)p->worker_init, p->data,
568c0222695SGlenn Strauss 					offsets[PLUGIN_FUNC_WORKER_INIT]);
569bcdc6a3bSJan Kneschke 	}
570bcdc6a3bSJan Kneschke 
5719974b57aSGlenn Strauss 	/* reverse cleanup lists to balance ctor/dtor-like plugin behaviors */
5729974b57aSGlenn Strauss 	plugins_call_init_reverse(srv,offsets[PLUGIN_FUNC_HANDLE_REQUEST_RESET]);
5739974b57aSGlenn Strauss 	plugins_call_init_reverse(srv,offsets[PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE]);
5749974b57aSGlenn Strauss 
575bcdc6a3bSJan Kneschke 	return HANDLER_GO_ON;
576bcdc6a3bSJan Kneschke }
577bcdc6a3bSJan Kneschke 
plugins_free(server * srv)578bcdc6a3bSJan Kneschke void plugins_free(server *srv) {
57962e97967SGlenn Strauss 	if (srv->plugin_slots) {
58062e97967SGlenn Strauss 		plugins_call_cleanup(srv);
58162e97967SGlenn Strauss 		free(srv->plugin_slots);
58262e97967SGlenn Strauss 		srv->plugin_slots = NULL;
58362e97967SGlenn Strauss 	}
584bcdc6a3bSJan Kneschke 
58562e97967SGlenn Strauss 	for (uint32_t i = 0; i < srv->plugins.used; ++i) {
586c0222695SGlenn Strauss 		plugin_free(((plugin **)srv->plugins.ptr)[i]);
587bcdc6a3bSJan Kneschke 	}
588bcdc6a3bSJan Kneschke 	free(srv->plugins.ptr);
589bcdc6a3bSJan Kneschke 	srv->plugins.ptr = NULL;
590b37a9585SmOo 	srv->plugins.used = 0;
591f24e6d69SGlenn Strauss 	array_free_data(&plugin_stats);
592bcdc6a3bSJan Kneschke }
593