[mod_cgi] fix pipe_cloexec() when no O_CLOEXEC
[lighttpd.git] / src / plugin.c
blobef9241cd01e018b53b6777a156ba29e0f79a6330
1 #include "first.h"
3 #include "plugin.h"
4 #include "log.h"
6 #include <string.h>
7 #include <stdlib.h>
9 #include <stdio.h>
11 #ifdef HAVE_VALGRIND_VALGRIND_H
12 # include <valgrind/valgrind.h>
13 #endif
15 #if !defined(__WIN32) && !defined(LIGHTTPD_STATIC)
16 # include <dlfcn.h>
17 #endif
20 * if you change this enum to add a new callback, be sure
21 * - that PLUGIN_FUNC_SIZEOF is the last entry
22 * - that you add PLUGIN_TO_SLOT twice:
23 * 1. as callback-dispatcher
24 * 2. in plugins_call_init()
28 typedef struct {
29 PLUGIN_DATA;
30 } plugin_data;
32 typedef enum {
33 PLUGIN_FUNC_UNSET,
35 PLUGIN_FUNC_HANDLE_URI_CLEAN,
36 PLUGIN_FUNC_HANDLE_URI_RAW,
37 PLUGIN_FUNC_HANDLE_REQUEST_DONE,
38 PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE,
39 PLUGIN_FUNC_HANDLE_TRIGGER,
40 PLUGIN_FUNC_HANDLE_SIGHUP,
41 PLUGIN_FUNC_HANDLE_SUBREQUEST,
42 PLUGIN_FUNC_HANDLE_SUBREQUEST_START,
43 PLUGIN_FUNC_HANDLE_RESPONSE_START,
44 PLUGIN_FUNC_HANDLE_DOCROOT,
45 PLUGIN_FUNC_HANDLE_PHYSICAL,
46 PLUGIN_FUNC_CONNECTION_RESET,
47 PLUGIN_FUNC_INIT,
48 PLUGIN_FUNC_CLEANUP,
49 PLUGIN_FUNC_SET_DEFAULTS,
51 PLUGIN_FUNC_SIZEOF
52 } plugin_t;
54 static plugin *plugin_init(void) {
55 plugin *p;
57 p = calloc(1, sizeof(*p));
58 force_assert(NULL != p);
60 return p;
63 static void plugin_free(plugin *p) {
64 #if !defined(LIGHTTPD_STATIC)
65 int use_dlclose = 1;
66 #endif
68 if (p->name) buffer_free(p->name);
69 #if defined(HAVE_VALGRIND_VALGRIND_H) && !defined(LIGHTTPD_STATIC)
70 /*if (RUNNING_ON_VALGRIND) use_dlclose = 0;*/
71 #endif
73 #if !defined(LIGHTTPD_STATIC)
74 if (use_dlclose && p->lib) {
75 #if defined(__WIN32)
76 ) FreeLibrary(p->lib);
77 #else
78 dlclose(p->lib);
79 #endif
81 #endif
83 free(p);
86 static int plugins_register(server *srv, plugin *p) {
87 plugin **ps;
88 if (0 == srv->plugins.size) {
89 srv->plugins.size = 4;
90 srv->plugins.ptr = malloc(srv->plugins.size * sizeof(*ps));
91 force_assert(NULL != srv->plugins.ptr);
92 srv->plugins.used = 0;
93 } else if (srv->plugins.used == srv->plugins.size) {
94 srv->plugins.size += 4;
95 srv->plugins.ptr = realloc(srv->plugins.ptr, srv->plugins.size * sizeof(*ps));
96 force_assert(NULL != srv->plugins.ptr);
99 ps = srv->plugins.ptr;
100 ps[srv->plugins.used++] = p;
102 return 0;
111 #if defined(LIGHTTPD_STATIC)
113 /* pre-declare functions, as there is no header for them */
114 #define PLUGIN_INIT(x)\
115 int x ## _plugin_init(plugin *p);
117 #include "plugin-static.h"
119 #undef PLUGIN_INIT
121 /* build NULL-terminated table of name + init-function */
123 typedef struct {
124 const char* name;
125 int (*plugin_init)(plugin *p);
126 } plugin_load_functions;
128 static const plugin_load_functions load_functions[] = {
129 #define PLUGIN_INIT(x) \
130 { #x, &x ## _plugin_init },
132 #include "plugin-static.h"
134 { NULL, NULL }
135 #undef PLUGIN_INIT
138 int plugins_load(server *srv) {
139 plugin *p;
140 size_t i, j;
142 for (i = 0; i < srv->srvconf.modules->used; i++) {
143 data_string *d = (data_string *)srv->srvconf.modules->data[i];
144 char *module = d->value->ptr;
146 for (j = 0; j < i; j++) {
147 if (buffer_is_equal(d->value, ((data_string *) srv->srvconf.modules->data[j])->value)) {
148 log_error_write(srv, __FILE__, __LINE__, "sbs",
149 "Cannot load plugin", d->value,
150 "more than once, please fix your config (lighttpd may not accept such configs in future releases)");
151 continue;
155 for (j = 0; load_functions[j].name; ++j) {
156 if (0 == strcmp(load_functions[j].name, module)) {
157 p = plugin_init();
158 if ((*load_functions[j].plugin_init)(p)) {
159 log_error_write(srv, __FILE__, __LINE__, "ss", module, "plugin init failed" );
160 plugin_free(p);
161 return -1;
163 plugins_register(srv, p);
164 break;
167 if (!load_functions[j].name) {
168 log_error_write(srv, __FILE__, __LINE__, "ss", module, " plugin not found" );
169 return -1;
173 return 0;
175 #else /* defined(LIGHTTPD_STATIC) */
176 int plugins_load(server *srv) {
177 plugin *p;
178 int (*init)(plugin *pl);
179 size_t i, j;
181 for (i = 0; i < srv->srvconf.modules->used; i++) {
182 data_string *d = (data_string *)srv->srvconf.modules->data[i];
183 char *module = d->value->ptr;
185 for (j = 0; j < i; j++) {
186 if (buffer_is_equal(d->value, ((data_string *) srv->srvconf.modules->data[j])->value)) {
187 log_error_write(srv, __FILE__, __LINE__, "sbs",
188 "Cannot load plugin", d->value,
189 "more than once, please fix your config (lighttpd may not accept such configs in future releases)");
190 continue;
194 buffer_copy_buffer(srv->tmp_buf, srv->srvconf.modules_dir);
196 buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("/"));
197 buffer_append_string(srv->tmp_buf, module);
198 #if defined(__WIN32) || defined(__CYGWIN__)
199 buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN(".dll"));
200 #else
201 buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN(".so"));
202 #endif
204 p = plugin_init();
205 #ifdef __WIN32
206 if (NULL == (p->lib = LoadLibrary(srv->tmp_buf->ptr))) {
207 LPVOID lpMsgBuf;
208 FormatMessage(
209 FORMAT_MESSAGE_ALLOCATE_BUFFER |
210 FORMAT_MESSAGE_FROM_SYSTEM,
211 NULL,
212 GetLastError(),
213 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
214 (LPTSTR) &lpMsgBuf,
215 0, NULL);
217 log_error_write(srv, __FILE__, __LINE__, "ssb", "LoadLibrary() failed",
218 lpMsgBuf, srv->tmp_buf);
220 plugin_free(p);
222 return -1;
225 #else
226 if (NULL == (p->lib = dlopen(srv->tmp_buf->ptr, RTLD_NOW|RTLD_GLOBAL))) {
227 log_error_write(srv, __FILE__, __LINE__, "sbs", "dlopen() failed for:",
228 srv->tmp_buf, dlerror());
230 plugin_free(p);
232 return -1;
235 #endif
236 buffer_reset(srv->tmp_buf);
237 buffer_copy_string(srv->tmp_buf, module);
238 buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("_plugin_init"));
240 #ifdef __WIN32
241 init = GetProcAddress(p->lib, srv->tmp_buf->ptr);
243 if (init == NULL) {
244 LPVOID lpMsgBuf;
245 FormatMessage(
246 FORMAT_MESSAGE_ALLOCATE_BUFFER |
247 FORMAT_MESSAGE_FROM_SYSTEM,
248 NULL,
249 GetLastError(),
250 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
251 (LPTSTR) &lpMsgBuf,
252 0, NULL);
254 log_error_write(srv, __FILE__, __LINE__, "sbs", "getprocaddress failed:", srv->tmp_buf, lpMsgBuf);
256 plugin_free(p);
257 return -1;
260 #else
261 #if 1
262 init = (int (*)(plugin *))(intptr_t)dlsym(p->lib, srv->tmp_buf->ptr);
263 #else
264 *(void **)(&init) = dlsym(p->lib, srv->tmp_buf->ptr);
265 #endif
266 if (NULL == init) {
267 const char *error = dlerror();
268 if (error != NULL) {
269 log_error_write(srv, __FILE__, __LINE__, "ss", "dlsym:", error);
270 } else {
271 log_error_write(srv, __FILE__, __LINE__, "ss", "dlsym symbol not found:", srv->tmp_buf->ptr);
274 plugin_free(p);
275 return -1;
278 #endif
279 if ((*init)(p)) {
280 log_error_write(srv, __FILE__, __LINE__, "ss", module, "plugin init failed" );
282 plugin_free(p);
283 return -1;
285 #if 0
286 log_error_write(srv, __FILE__, __LINE__, "ss", module, "plugin loaded" );
287 #endif
288 plugins_register(srv, p);
291 return 0;
293 #endif /* defined(LIGHTTPD_STATIC) */
295 #define PLUGIN_TO_SLOT(x, y) \
296 handler_t plugins_call_##y(server *srv, connection *con) {\
297 plugin **slot;\
298 size_t j;\
299 if (!srv->plugin_slots) return HANDLER_GO_ON;\
300 slot = ((plugin ***)(srv->plugin_slots))[x];\
301 if (!slot) return HANDLER_GO_ON;\
302 for (j = 0; j < srv->plugins.used && slot[j]; j++) { \
303 plugin *p = slot[j];\
304 handler_t r;\
305 switch(r = p->y(srv, con, p->data)) {\
306 case HANDLER_GO_ON:\
307 break;\
308 case HANDLER_FINISHED:\
309 case HANDLER_COMEBACK:\
310 case HANDLER_WAIT_FOR_EVENT:\
311 case HANDLER_WAIT_FOR_FD:\
312 case HANDLER_ERROR:\
313 return r;\
314 default:\
315 log_error_write(srv, __FILE__, __LINE__, "sbs", #x, p->name, "unknown state");\
316 return HANDLER_ERROR;\
319 return HANDLER_GO_ON;\
323 * plugins that use
325 * - server *srv
326 * - connection *con
327 * - void *p_d (plugin_data *)
330 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean)
331 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw)
332 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done)
333 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close)
334 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST, handle_subrequest)
335 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST_START, handle_subrequest_start)
336 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_RESPONSE_START, handle_response_start)
337 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot)
338 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical)
339 PLUGIN_TO_SLOT(PLUGIN_FUNC_CONNECTION_RESET, connection_reset)
341 #undef PLUGIN_TO_SLOT
343 #define PLUGIN_TO_SLOT(x, y) \
344 handler_t plugins_call_##y(server *srv) {\
345 plugin **slot;\
346 size_t j;\
347 if (!srv->plugin_slots) return HANDLER_GO_ON;\
348 slot = ((plugin ***)(srv->plugin_slots))[x];\
349 if (!slot) return HANDLER_GO_ON;\
350 for (j = 0; j < srv->plugins.used && slot[j]; j++) { \
351 plugin *p = slot[j];\
352 handler_t r;\
353 switch(r = p->y(srv, p->data)) {\
354 case HANDLER_GO_ON:\
355 break;\
356 case HANDLER_FINISHED:\
357 case HANDLER_COMEBACK:\
358 case HANDLER_WAIT_FOR_EVENT:\
359 case HANDLER_WAIT_FOR_FD:\
360 case HANDLER_ERROR:\
361 return r;\
362 default:\
363 log_error_write(srv, __FILE__, __LINE__, "sbsd", #x, p->name, "unknown state:", r);\
364 return HANDLER_ERROR;\
367 return HANDLER_GO_ON;\
371 * plugins that use
373 * - server *srv
374 * - void *p_d (plugin_data *)
377 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger)
378 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup)
379 PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup)
380 PLUGIN_TO_SLOT(PLUGIN_FUNC_SET_DEFAULTS, set_defaults)
382 #undef PLUGIN_TO_SLOT
384 #if 0
387 * special handler
390 handler_t plugins_call_handle_fdevent(server *srv, const fd_conn *fdc) {
391 size_t i;
392 plugin **ps;
394 ps = srv->plugins.ptr;
396 for (i = 0; i < srv->plugins.used; i++) {
397 plugin *p = ps[i];
398 if (p->handle_fdevent) {
399 handler_t r;
400 switch(r = p->handle_fdevent(srv, fdc, p->data)) {
401 case HANDLER_GO_ON:
402 break;
403 case HANDLER_FINISHED:
404 case HANDLER_COMEBACK:
405 case HANDLER_WAIT_FOR_EVENT:
406 case HANDLER_ERROR:
407 return r;
408 default:
409 log_error_write(srv, __FILE__, __LINE__, "d", r);
410 break;
415 return HANDLER_GO_ON;
417 #endif
420 * - call init function of all plugins to init the plugin-internals
421 * - added each plugin that supports has callback to the corresponding slot
423 * - is only called once.
426 handler_t plugins_call_init(server *srv) {
427 size_t i;
428 plugin **ps;
430 ps = srv->plugins.ptr;
432 /* fill slots */
434 srv->plugin_slots = calloc(PLUGIN_FUNC_SIZEOF, sizeof(ps));
435 force_assert(NULL != srv->plugin_slots);
437 for (i = 0; i < srv->plugins.used; i++) {
438 size_t j;
439 /* check which calls are supported */
441 plugin *p = ps[i];
443 #define PLUGIN_TO_SLOT(x, y) \
444 if (p->y) { \
445 plugin **slot = ((plugin ***)(srv->plugin_slots))[x]; \
446 if (!slot) { \
447 slot = calloc(srv->plugins.used, sizeof(*slot));\
448 force_assert(NULL != slot); \
449 ((plugin ***)(srv->plugin_slots))[x] = slot; \
451 for (j = 0; j < srv->plugins.used; j++) { \
452 if (slot[j]) continue;\
453 slot[j] = p;\
454 break;\
459 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean);
460 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw);
461 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done);
462 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close);
463 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger);
464 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup);
465 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST, handle_subrequest);
466 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST_START, handle_subrequest_start);
467 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_RESPONSE_START, handle_response_start);
468 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot);
469 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical);
470 PLUGIN_TO_SLOT(PLUGIN_FUNC_CONNECTION_RESET, connection_reset);
471 PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup);
472 PLUGIN_TO_SLOT(PLUGIN_FUNC_SET_DEFAULTS, set_defaults);
473 #undef PLUGIN_TO_SLOT
475 if (p->init) {
476 if (NULL == (p->data = p->init())) {
477 log_error_write(srv, __FILE__, __LINE__, "sb",
478 "plugin-init failed for module", p->name);
479 return HANDLER_ERROR;
482 /* used for con->mode, DIRECT == 0, plugins above that */
483 ((plugin_data *)(p->data))->id = i + 1;
485 if (p->version != LIGHTTPD_VERSION_ID) {
486 log_error_write(srv, __FILE__, __LINE__, "sb",
487 "plugin-version doesn't match lighttpd-version for", p->name);
488 return HANDLER_ERROR;
490 } else {
491 p->data = NULL;
495 return HANDLER_GO_ON;
498 void plugins_free(server *srv) {
499 size_t i;
500 plugins_call_cleanup(srv);
502 for (i = 0; i < srv->plugins.used; i++) {
503 plugin *p = ((plugin **)srv->plugins.ptr)[i];
505 plugin_free(p);
508 for (i = 0; srv->plugin_slots && i < PLUGIN_FUNC_SIZEOF; i++) {
509 plugin **slot = ((plugin ***)(srv->plugin_slots))[i];
511 if (slot) free(slot);
514 free(srv->plugin_slots);
515 srv->plugin_slots = NULL;
517 free(srv->plugins.ptr);
518 srv->plugins.ptr = NULL;
519 srv->plugins.used = 0;