[mod_openssl] remove erroneous SSL_set_shutdown()
[lighttpd.git] / src / plugin.c
blob20aec918f71a212f87759d1026accb55d2a9cc55
1 #include "first.h"
3 #include "plugin.h"
4 #include "log.h"
6 #include <string.h>
7 #include <stdlib.h>
9 #ifdef HAVE_VALGRIND_VALGRIND_H
10 # include <valgrind/valgrind.h>
11 #endif
13 #if !defined(__WIN32) && !defined(LIGHTTPD_STATIC)
14 # include <dlfcn.h>
15 #endif
18 * if you change this enum to add a new callback, be sure
19 * - that PLUGIN_FUNC_SIZEOF is the last entry
20 * - that you add PLUGIN_TO_SLOT twice:
21 * 1. as callback-dispatcher
22 * 2. in plugins_call_init()
26 typedef struct {
27 PLUGIN_DATA;
28 } plugin_data;
30 typedef enum {
31 PLUGIN_FUNC_UNSET,
33 PLUGIN_FUNC_HANDLE_URI_CLEAN,
34 PLUGIN_FUNC_HANDLE_URI_RAW,
35 PLUGIN_FUNC_HANDLE_REQUEST_ENV,
36 PLUGIN_FUNC_HANDLE_REQUEST_DONE,
37 PLUGIN_FUNC_HANDLE_CONNECTION_ACCEPT,
38 PLUGIN_FUNC_HANDLE_CONNECTION_SHUT_WR,
39 PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE,
40 PLUGIN_FUNC_HANDLE_TRIGGER,
41 PLUGIN_FUNC_HANDLE_SIGHUP,
42 PLUGIN_FUNC_HANDLE_WAITPID,
43 PLUGIN_FUNC_HANDLE_SUBREQUEST,
44 PLUGIN_FUNC_HANDLE_SUBREQUEST_START,
45 PLUGIN_FUNC_HANDLE_RESPONSE_START,
46 PLUGIN_FUNC_HANDLE_DOCROOT,
47 PLUGIN_FUNC_HANDLE_PHYSICAL,
48 PLUGIN_FUNC_CONNECTION_RESET,
49 PLUGIN_FUNC_INIT,
50 PLUGIN_FUNC_CLEANUP,
51 PLUGIN_FUNC_SET_DEFAULTS,
53 PLUGIN_FUNC_SIZEOF
54 } plugin_t;
56 static plugin *plugin_init(void) {
57 plugin *p;
59 p = calloc(1, sizeof(*p));
60 force_assert(NULL != p);
62 return p;
65 static void plugin_free(plugin *p) {
66 #if !defined(LIGHTTPD_STATIC)
67 int use_dlclose = 1;
68 #endif
70 if (p->name) buffer_free(p->name);
71 #if defined(HAVE_VALGRIND_VALGRIND_H) && !defined(LIGHTTPD_STATIC)
72 /*if (RUNNING_ON_VALGRIND) use_dlclose = 0;*/
73 #endif
75 #if !defined(LIGHTTPD_STATIC)
76 if (use_dlclose && p->lib) {
77 #if defined(__WIN32)
78 ) FreeLibrary(p->lib);
79 #else
80 dlclose(p->lib);
81 #endif
83 #endif
85 free(p);
88 static int plugins_register(server *srv, plugin *p) {
89 plugin **ps;
90 if (0 == srv->plugins.size) {
91 srv->plugins.size = 4;
92 srv->plugins.ptr = malloc(srv->plugins.size * sizeof(*ps));
93 force_assert(NULL != srv->plugins.ptr);
94 srv->plugins.used = 0;
95 } else if (srv->plugins.used == srv->plugins.size) {
96 srv->plugins.size += 4;
97 srv->plugins.ptr = realloc(srv->plugins.ptr, srv->plugins.size * sizeof(*ps));
98 force_assert(NULL != srv->plugins.ptr);
101 ps = srv->plugins.ptr;
102 ps[srv->plugins.used++] = p;
104 return 0;
113 #if defined(LIGHTTPD_STATIC)
115 /* pre-declare functions, as there is no header for them */
116 #define PLUGIN_INIT(x)\
117 int x ## _plugin_init(plugin *p);
119 #include "plugin-static.h"
121 #undef PLUGIN_INIT
123 /* build NULL-terminated table of name + init-function */
125 typedef struct {
126 const char* name;
127 int (*plugin_init)(plugin *p);
128 } plugin_load_functions;
130 static const plugin_load_functions load_functions[] = {
131 #define PLUGIN_INIT(x) \
132 { #x, &x ## _plugin_init },
134 #include "plugin-static.h"
136 { NULL, NULL }
137 #undef PLUGIN_INIT
140 int plugins_load(server *srv) {
141 plugin *p;
142 size_t i, j;
144 for (i = 0; i < srv->srvconf.modules->used; i++) {
145 data_string *d = (data_string *)srv->srvconf.modules->data[i];
146 char *module = d->value->ptr;
148 for (j = 0; j < i; j++) {
149 if (buffer_is_equal(d->value, ((data_string *) srv->srvconf.modules->data[j])->value)) {
150 log_error_write(srv, __FILE__, __LINE__, "sbs",
151 "Cannot load plugin", d->value,
152 "more than once, please fix your config (lighttpd may not accept such configs in future releases)");
153 continue;
157 for (j = 0; load_functions[j].name; ++j) {
158 if (0 == strcmp(load_functions[j].name, module)) {
159 p = plugin_init();
160 if ((*load_functions[j].plugin_init)(p)) {
161 log_error_write(srv, __FILE__, __LINE__, "ss", module, "plugin init failed" );
162 plugin_free(p);
163 return -1;
165 plugins_register(srv, p);
166 break;
169 if (!load_functions[j].name) {
170 log_error_write(srv, __FILE__, __LINE__, "ss", module, " plugin not found" );
171 return -1;
175 return 0;
177 #else /* defined(LIGHTTPD_STATIC) */
178 int plugins_load(server *srv) {
179 plugin *p;
180 int (*init)(plugin *pl);
181 size_t i, j;
183 for (i = 0; i < srv->srvconf.modules->used; i++) {
184 data_string *d = (data_string *)srv->srvconf.modules->data[i];
185 char *module = d->value->ptr;
187 for (j = 0; j < i; j++) {
188 if (buffer_is_equal(d->value, ((data_string *) srv->srvconf.modules->data[j])->value)) {
189 log_error_write(srv, __FILE__, __LINE__, "sbs",
190 "Cannot load plugin", d->value,
191 "more than once, please fix your config (lighttpd may not accept such configs in future releases)");
192 continue;
196 buffer_copy_buffer(srv->tmp_buf, srv->srvconf.modules_dir);
198 buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("/"));
199 buffer_append_string(srv->tmp_buf, module);
200 #if defined(__WIN32) || defined(__CYGWIN__)
201 buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN(".dll"));
202 #else
203 buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN(".so"));
204 #endif
206 p = plugin_init();
207 #ifdef __WIN32
208 if (NULL == (p->lib = LoadLibrary(srv->tmp_buf->ptr))) {
209 LPVOID lpMsgBuf;
210 FormatMessage(
211 FORMAT_MESSAGE_ALLOCATE_BUFFER |
212 FORMAT_MESSAGE_FROM_SYSTEM,
213 NULL,
214 GetLastError(),
215 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
216 (LPTSTR) &lpMsgBuf,
217 0, NULL);
219 log_error_write(srv, __FILE__, __LINE__, "ssb", "LoadLibrary() failed",
220 lpMsgBuf, srv->tmp_buf);
222 plugin_free(p);
224 return -1;
227 #else
228 if (NULL == (p->lib = dlopen(srv->tmp_buf->ptr, RTLD_NOW|RTLD_GLOBAL))) {
229 log_error_write(srv, __FILE__, __LINE__, "sbs", "dlopen() failed for:",
230 srv->tmp_buf, dlerror());
232 plugin_free(p);
234 return -1;
237 #endif
238 buffer_reset(srv->tmp_buf);
239 buffer_copy_string(srv->tmp_buf, module);
240 buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("_plugin_init"));
242 #ifdef __WIN32
243 init = GetProcAddress(p->lib, srv->tmp_buf->ptr);
245 if (init == NULL) {
246 LPVOID lpMsgBuf;
247 FormatMessage(
248 FORMAT_MESSAGE_ALLOCATE_BUFFER |
249 FORMAT_MESSAGE_FROM_SYSTEM,
250 NULL,
251 GetLastError(),
252 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
253 (LPTSTR) &lpMsgBuf,
254 0, NULL);
256 log_error_write(srv, __FILE__, __LINE__, "sbs", "getprocaddress failed:", srv->tmp_buf, lpMsgBuf);
258 plugin_free(p);
259 return -1;
262 #else
263 #if 1
264 init = (int (*)(plugin *))(intptr_t)dlsym(p->lib, srv->tmp_buf->ptr);
265 #else
266 *(void **)(&init) = dlsym(p->lib, srv->tmp_buf->ptr);
267 #endif
268 if (NULL == init) {
269 const char *error = dlerror();
270 if (error != NULL) {
271 log_error_write(srv, __FILE__, __LINE__, "ss", "dlsym:", error);
272 } else {
273 log_error_write(srv, __FILE__, __LINE__, "ss", "dlsym symbol not found:", srv->tmp_buf->ptr);
276 plugin_free(p);
277 return -1;
280 #endif
281 if ((*init)(p)) {
282 log_error_write(srv, __FILE__, __LINE__, "ss", module, "plugin init failed" );
284 plugin_free(p);
285 return -1;
287 #if 0
288 log_error_write(srv, __FILE__, __LINE__, "ss", module, "plugin loaded" );
289 #endif
290 plugins_register(srv, p);
293 return 0;
295 #endif /* defined(LIGHTTPD_STATIC) */
297 #define PLUGIN_TO_SLOT(x, y) \
298 handler_t plugins_call_##y(server *srv, connection *con) {\
299 plugin **slot;\
300 size_t j;\
301 slot = ((plugin ***)(srv->plugin_slots))[x];\
302 if (!slot) return HANDLER_GO_ON;\
303 for (j = 0; j < srv->plugins.used && slot[j]; j++) { \
304 plugin *p = slot[j];\
305 handler_t r;\
306 switch(r = p->y(srv, con, p->data)) {\
307 case HANDLER_GO_ON:\
308 break;\
309 case HANDLER_FINISHED:\
310 case HANDLER_COMEBACK:\
311 case HANDLER_WAIT_FOR_EVENT:\
312 case HANDLER_WAIT_FOR_FD:\
313 case HANDLER_ERROR:\
314 return r;\
315 default:\
316 log_error_write(srv, __FILE__, __LINE__, "sbs", #x, p->name, "unknown state");\
317 return HANDLER_ERROR;\
320 return HANDLER_GO_ON;\
324 * plugins that use
326 * - server *srv
327 * - connection *con
328 * - void *p_d (plugin_data *)
331 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean)
332 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw)
333 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_ENV, handle_request_env)
334 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done)
335 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_ACCEPT, handle_connection_accept)
336 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_SHUT_WR, handle_connection_shut_wr)
337 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close)
338 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST, handle_subrequest)
339 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST_START, handle_subrequest_start)
340 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_RESPONSE_START, handle_response_start)
341 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot)
342 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical)
343 PLUGIN_TO_SLOT(PLUGIN_FUNC_CONNECTION_RESET, connection_reset)
345 #undef PLUGIN_TO_SLOT
347 #define PLUGIN_TO_SLOT(x, y) \
348 handler_t plugins_call_##y(server *srv) {\
349 plugin **slot;\
350 size_t j;\
351 if (!srv->plugin_slots) return HANDLER_GO_ON;\
352 slot = ((plugin ***)(srv->plugin_slots))[x];\
353 if (!slot) return HANDLER_GO_ON;\
354 for (j = 0; j < srv->plugins.used && slot[j]; j++) { \
355 plugin *p = slot[j];\
356 handler_t r;\
357 switch(r = p->y(srv, p->data)) {\
358 case HANDLER_GO_ON:\
359 break;\
360 case HANDLER_FINISHED:\
361 case HANDLER_COMEBACK:\
362 case HANDLER_WAIT_FOR_EVENT:\
363 case HANDLER_WAIT_FOR_FD:\
364 case HANDLER_ERROR:\
365 return r;\
366 default:\
367 log_error_write(srv, __FILE__, __LINE__, "sbsd", #x, p->name, "unknown state:", r);\
368 return HANDLER_ERROR;\
371 return HANDLER_GO_ON;\
375 * plugins that use
377 * - server *srv
378 * - void *p_d (plugin_data *)
381 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger)
382 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup)
383 PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup)
384 PLUGIN_TO_SLOT(PLUGIN_FUNC_SET_DEFAULTS, set_defaults)
386 #undef PLUGIN_TO_SLOT
388 handler_t plugins_call_handle_waitpid(server *srv, pid_t pid, int status) {
389 plugin ** const slot =
390 ((plugin ***)(srv->plugin_slots))[PLUGIN_FUNC_HANDLE_WAITPID];
391 if (!slot) return HANDLER_GO_ON;
392 for (size_t i = 0; i < srv->plugins.used && slot[i]; ++i) {
393 plugin *p = slot[i];
394 handler_t r = p->handle_waitpid(srv, p->data, pid, status);
395 if (r != HANDLER_GO_ON) return r;
397 return HANDLER_GO_ON;
400 #if 0
403 * special handler
406 handler_t plugins_call_handle_fdevent(server *srv, const fd_conn *fdc) {
407 size_t i;
408 plugin **ps;
410 ps = srv->plugins.ptr;
412 for (i = 0; i < srv->plugins.used; i++) {
413 plugin *p = ps[i];
414 if (p->handle_fdevent) {
415 handler_t r;
416 switch(r = p->handle_fdevent(srv, fdc, p->data)) {
417 case HANDLER_GO_ON:
418 break;
419 case HANDLER_FINISHED:
420 case HANDLER_COMEBACK:
421 case HANDLER_WAIT_FOR_EVENT:
422 case HANDLER_ERROR:
423 return r;
424 default:
425 log_error_write(srv, __FILE__, __LINE__, "d", r);
426 break;
431 return HANDLER_GO_ON;
433 #endif
436 * - call init function of all plugins to init the plugin-internals
437 * - added each plugin that supports has callback to the corresponding slot
439 * - is only called once.
442 handler_t plugins_call_init(server *srv) {
443 size_t i;
444 plugin **ps;
446 ps = srv->plugins.ptr;
448 /* fill slots */
450 srv->plugin_slots = calloc(PLUGIN_FUNC_SIZEOF, sizeof(ps));
451 force_assert(NULL != srv->plugin_slots);
453 for (i = 0; i < srv->plugins.used; i++) {
454 size_t j;
455 /* check which calls are supported */
457 plugin *p = ps[i];
459 #define PLUGIN_TO_SLOT(x, y) \
460 if (p->y) { \
461 plugin **slot = ((plugin ***)(srv->plugin_slots))[x]; \
462 if (!slot) { \
463 slot = calloc(srv->plugins.used, sizeof(*slot));\
464 force_assert(NULL != slot); \
465 ((plugin ***)(srv->plugin_slots))[x] = slot; \
467 for (j = 0; j < srv->plugins.used; j++) { \
468 if (slot[j]) continue;\
469 slot[j] = p;\
470 break;\
475 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean);
476 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw);
477 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_ENV, handle_request_env);
478 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done);
479 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_ACCEPT, handle_connection_accept);
480 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_SHUT_WR, handle_connection_shut_wr);
481 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close);
482 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger);
483 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup);
484 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_WAITPID, handle_waitpid);
485 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST, handle_subrequest);
486 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST_START, handle_subrequest_start);
487 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_RESPONSE_START, handle_response_start);
488 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot);
489 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical);
490 PLUGIN_TO_SLOT(PLUGIN_FUNC_CONNECTION_RESET, connection_reset);
491 PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup);
492 PLUGIN_TO_SLOT(PLUGIN_FUNC_SET_DEFAULTS, set_defaults);
493 #undef PLUGIN_TO_SLOT
495 if (p->init) {
496 if (NULL == (p->data = p->init())) {
497 log_error_write(srv, __FILE__, __LINE__, "sb",
498 "plugin-init failed for module", p->name);
499 return HANDLER_ERROR;
502 /* used for con->mode, DIRECT == 0, plugins above that */
503 ((plugin_data *)(p->data))->id = i + 1;
505 if (p->version != LIGHTTPD_VERSION_ID) {
506 log_error_write(srv, __FILE__, __LINE__, "sb",
507 "plugin-version doesn't match lighttpd-version for", p->name);
508 return HANDLER_ERROR;
510 } else {
511 p->data = NULL;
514 if (p->priv_defaults && HANDLER_ERROR==p->priv_defaults(srv, p->data)) {
515 return HANDLER_ERROR;
519 return HANDLER_GO_ON;
522 void plugins_free(server *srv) {
523 size_t i;
524 plugins_call_cleanup(srv);
526 for (i = 0; i < srv->plugins.used; i++) {
527 plugin *p = ((plugin **)srv->plugins.ptr)[i];
529 plugin_free(p);
532 for (i = 0; srv->plugin_slots && i < PLUGIN_FUNC_SIZEOF; i++) {
533 plugin **slot = ((plugin ***)(srv->plugin_slots))[i];
535 if (slot) free(slot);
538 free(srv->plugin_slots);
539 srv->plugin_slots = NULL;
541 free(srv->plugins.ptr);
542 srv->plugins.ptr = NULL;
543 srv->plugins.used = 0;