[mod_uploadprogress] fix mem leak (#1858)
[lighttpd.git] / src / plugin.c
blob638b46c6bb262ec38f0929ebd6027c7c979d786f
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_DOCROOT,
44 PLUGIN_FUNC_HANDLE_PHYSICAL,
45 PLUGIN_FUNC_CONNECTION_RESET,
46 PLUGIN_FUNC_INIT,
47 PLUGIN_FUNC_CLEANUP,
48 PLUGIN_FUNC_SET_DEFAULTS,
50 PLUGIN_FUNC_SIZEOF
51 } plugin_t;
53 static plugin *plugin_init(void) {
54 plugin *p;
56 p = calloc(1, sizeof(*p));
57 force_assert(NULL != p);
59 return p;
62 static void plugin_free(plugin *p) {
63 #if !defined(LIGHTTPD_STATIC)
64 int use_dlclose = 1;
65 #endif
67 if (p->name) buffer_free(p->name);
68 #if defined(HAVE_VALGRIND_VALGRIND_H) && !defined(LIGHTTPD_STATIC)
69 /*if (RUNNING_ON_VALGRIND) use_dlclose = 0;*/
70 #endif
72 #if !defined(LIGHTTPD_STATIC)
73 if (use_dlclose && p->lib) {
74 #if defined(__WIN32)
75 ) FreeLibrary(p->lib);
76 #else
77 dlclose(p->lib);
78 #endif
80 #endif
82 free(p);
85 static int plugins_register(server *srv, plugin *p) {
86 plugin **ps;
87 if (0 == srv->plugins.size) {
88 srv->plugins.size = 4;
89 srv->plugins.ptr = malloc(srv->plugins.size * sizeof(*ps));
90 force_assert(NULL != srv->plugins.ptr);
91 srv->plugins.used = 0;
92 } else if (srv->plugins.used == srv->plugins.size) {
93 srv->plugins.size += 4;
94 srv->plugins.ptr = realloc(srv->plugins.ptr, srv->plugins.size * sizeof(*ps));
95 force_assert(NULL != srv->plugins.ptr);
98 ps = srv->plugins.ptr;
99 ps[srv->plugins.used++] = p;
101 return 0;
110 #if defined(LIGHTTPD_STATIC)
112 /* pre-declare functions, as there is no header for them */
113 #define PLUGIN_INIT(x)\
114 int x ## _plugin_init(plugin *p);
116 #include "plugin-static.h"
118 #undef PLUGIN_INIT
120 /* build NULL-terminated table of name + init-function */
122 typedef struct {
123 const char* name;
124 int (*plugin_init)(plugin *p);
125 } plugin_load_functions;
127 static const plugin_load_functions load_functions[] = {
128 #define PLUGIN_INIT(x) \
129 { #x, &x ## _plugin_init },
131 #include "plugin-static.h"
133 { NULL, NULL }
134 #undef PLUGIN_INIT
137 int plugins_load(server *srv) {
138 plugin *p;
139 size_t i, j;
141 for (i = 0; i < srv->srvconf.modules->used; i++) {
142 data_string *d = (data_string *)srv->srvconf.modules->data[i];
143 char *module = d->value->ptr;
145 for (j = 0; j < i; j++) {
146 if (buffer_is_equal(d->value, ((data_string *) srv->srvconf.modules->data[j])->value)) {
147 log_error_write(srv, __FILE__, __LINE__, "sbs",
148 "Cannot load plugin", d->value,
149 "more than once, please fix your config (lighttpd may not accept such configs in future releases)");
150 continue;
154 for (j = 0; load_functions[j].name; ++j) {
155 if (0 == strcmp(load_functions[j].name, module)) {
156 p = plugin_init();
157 if ((*load_functions[j].plugin_init)(p)) {
158 log_error_write(srv, __FILE__, __LINE__, "ss", module, "plugin init failed" );
159 plugin_free(p);
160 return -1;
162 plugins_register(srv, p);
163 break;
166 if (!load_functions[j].name) {
167 log_error_write(srv, __FILE__, __LINE__, "ss", module, " plugin not found" );
168 return -1;
172 return 0;
174 #else /* defined(LIGHTTPD_STATIC) */
175 int plugins_load(server *srv) {
176 plugin *p;
177 int (*init)(plugin *pl);
178 size_t i, j;
180 for (i = 0; i < srv->srvconf.modules->used; i++) {
181 data_string *d = (data_string *)srv->srvconf.modules->data[i];
182 char *module = d->value->ptr;
184 for (j = 0; j < i; j++) {
185 if (buffer_is_equal(d->value, ((data_string *) srv->srvconf.modules->data[j])->value)) {
186 log_error_write(srv, __FILE__, __LINE__, "sbs",
187 "Cannot load plugin", d->value,
188 "more than once, please fix your config (lighttpd may not accept such configs in future releases)");
189 continue;
193 buffer_copy_buffer(srv->tmp_buf, srv->srvconf.modules_dir);
195 buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("/"));
196 buffer_append_string(srv->tmp_buf, module);
197 #if defined(__WIN32) || defined(__CYGWIN__)
198 buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN(".dll"));
199 #else
200 buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN(".so"));
201 #endif
203 p = plugin_init();
204 #ifdef __WIN32
205 if (NULL == (p->lib = LoadLibrary(srv->tmp_buf->ptr))) {
206 LPVOID lpMsgBuf;
207 FormatMessage(
208 FORMAT_MESSAGE_ALLOCATE_BUFFER |
209 FORMAT_MESSAGE_FROM_SYSTEM,
210 NULL,
211 GetLastError(),
212 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
213 (LPTSTR) &lpMsgBuf,
214 0, NULL);
216 log_error_write(srv, __FILE__, __LINE__, "ssb", "LoadLibrary() failed",
217 lpMsgBuf, srv->tmp_buf);
219 plugin_free(p);
221 return -1;
224 #else
225 if (NULL == (p->lib = dlopen(srv->tmp_buf->ptr, RTLD_NOW|RTLD_GLOBAL))) {
226 log_error_write(srv, __FILE__, __LINE__, "sbs", "dlopen() failed for:",
227 srv->tmp_buf, dlerror());
229 plugin_free(p);
231 return -1;
234 #endif
235 buffer_reset(srv->tmp_buf);
236 buffer_copy_string(srv->tmp_buf, module);
237 buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("_plugin_init"));
239 #ifdef __WIN32
240 init = GetProcAddress(p->lib, srv->tmp_buf->ptr);
242 if (init == NULL) {
243 LPVOID lpMsgBuf;
244 FormatMessage(
245 FORMAT_MESSAGE_ALLOCATE_BUFFER |
246 FORMAT_MESSAGE_FROM_SYSTEM,
247 NULL,
248 GetLastError(),
249 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
250 (LPTSTR) &lpMsgBuf,
251 0, NULL);
253 log_error_write(srv, __FILE__, __LINE__, "sbs", "getprocaddress failed:", srv->tmp_buf, lpMsgBuf);
255 plugin_free(p);
256 return -1;
259 #else
260 #if 1
261 init = (int (*)(plugin *))(intptr_t)dlsym(p->lib, srv->tmp_buf->ptr);
262 #else
263 *(void **)(&init) = dlsym(p->lib, srv->tmp_buf->ptr);
264 #endif
265 if (NULL == init) {
266 const char *error = dlerror();
267 if (error != NULL) {
268 log_error_write(srv, __FILE__, __LINE__, "ss", "dlsym:", error);
269 } else {
270 log_error_write(srv, __FILE__, __LINE__, "ss", "dlsym symbol not found:", srv->tmp_buf->ptr);
273 plugin_free(p);
274 return -1;
277 #endif
278 if ((*init)(p)) {
279 log_error_write(srv, __FILE__, __LINE__, "ss", module, "plugin init failed" );
281 plugin_free(p);
282 return -1;
284 #if 0
285 log_error_write(srv, __FILE__, __LINE__, "ss", module, "plugin loaded" );
286 #endif
287 plugins_register(srv, p);
290 return 0;
292 #endif /* defined(LIGHTTPD_STATIC) */
294 #define PLUGIN_TO_SLOT(x, y) \
295 handler_t plugins_call_##y(server *srv, connection *con) {\
296 plugin **slot;\
297 size_t j;\
298 if (!srv->plugin_slots) return HANDLER_GO_ON;\
299 slot = ((plugin ***)(srv->plugin_slots))[x];\
300 if (!slot) return HANDLER_GO_ON;\
301 for (j = 0; j < srv->plugins.used && slot[j]; j++) { \
302 plugin *p = slot[j];\
303 handler_t r;\
304 switch(r = p->y(srv, con, p->data)) {\
305 case HANDLER_GO_ON:\
306 break;\
307 case HANDLER_FINISHED:\
308 case HANDLER_COMEBACK:\
309 case HANDLER_WAIT_FOR_EVENT:\
310 case HANDLER_WAIT_FOR_FD:\
311 case HANDLER_ERROR:\
312 return r;\
313 default:\
314 log_error_write(srv, __FILE__, __LINE__, "sbs", #x, p->name, "unknown state");\
315 return HANDLER_ERROR;\
318 return HANDLER_GO_ON;\
322 * plugins that use
324 * - server *srv
325 * - connection *con
326 * - void *p_d (plugin_data *)
329 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean)
330 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw)
331 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done)
332 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close)
333 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST, handle_subrequest)
334 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST_START, handle_subrequest_start)
335 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot)
336 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical)
337 PLUGIN_TO_SLOT(PLUGIN_FUNC_CONNECTION_RESET, connection_reset)
339 #undef PLUGIN_TO_SLOT
341 #define PLUGIN_TO_SLOT(x, y) \
342 handler_t plugins_call_##y(server *srv) {\
343 plugin **slot;\
344 size_t j;\
345 if (!srv->plugin_slots) return HANDLER_GO_ON;\
346 slot = ((plugin ***)(srv->plugin_slots))[x];\
347 if (!slot) return HANDLER_GO_ON;\
348 for (j = 0; j < srv->plugins.used && slot[j]; j++) { \
349 plugin *p = slot[j];\
350 handler_t r;\
351 switch(r = p->y(srv, p->data)) {\
352 case HANDLER_GO_ON:\
353 break;\
354 case HANDLER_FINISHED:\
355 case HANDLER_COMEBACK:\
356 case HANDLER_WAIT_FOR_EVENT:\
357 case HANDLER_WAIT_FOR_FD:\
358 case HANDLER_ERROR:\
359 return r;\
360 default:\
361 log_error_write(srv, __FILE__, __LINE__, "sbsd", #x, p->name, "unknown state:", r);\
362 return HANDLER_ERROR;\
365 return HANDLER_GO_ON;\
369 * plugins that use
371 * - server *srv
372 * - void *p_d (plugin_data *)
375 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger)
376 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup)
377 PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup)
378 PLUGIN_TO_SLOT(PLUGIN_FUNC_SET_DEFAULTS, set_defaults)
380 #undef PLUGIN_TO_SLOT
382 #if 0
385 * special handler
388 handler_t plugins_call_handle_fdevent(server *srv, const fd_conn *fdc) {
389 size_t i;
390 plugin **ps;
392 ps = srv->plugins.ptr;
394 for (i = 0; i < srv->plugins.used; i++) {
395 plugin *p = ps[i];
396 if (p->handle_fdevent) {
397 handler_t r;
398 switch(r = p->handle_fdevent(srv, fdc, p->data)) {
399 case HANDLER_GO_ON:
400 break;
401 case HANDLER_FINISHED:
402 case HANDLER_COMEBACK:
403 case HANDLER_WAIT_FOR_EVENT:
404 case HANDLER_ERROR:
405 return r;
406 default:
407 log_error_write(srv, __FILE__, __LINE__, "d", r);
408 break;
413 return HANDLER_GO_ON;
415 #endif
418 * - call init function of all plugins to init the plugin-internals
419 * - added each plugin that supports has callback to the corresponding slot
421 * - is only called once.
424 handler_t plugins_call_init(server *srv) {
425 size_t i;
426 plugin **ps;
428 ps = srv->plugins.ptr;
430 /* fill slots */
432 srv->plugin_slots = calloc(PLUGIN_FUNC_SIZEOF, sizeof(ps));
433 force_assert(NULL != srv->plugin_slots);
435 for (i = 0; i < srv->plugins.used; i++) {
436 size_t j;
437 /* check which calls are supported */
439 plugin *p = ps[i];
441 #define PLUGIN_TO_SLOT(x, y) \
442 if (p->y) { \
443 plugin **slot = ((plugin ***)(srv->plugin_slots))[x]; \
444 if (!slot) { \
445 slot = calloc(srv->plugins.used, sizeof(*slot));\
446 force_assert(NULL != slot); \
447 ((plugin ***)(srv->plugin_slots))[x] = slot; \
449 for (j = 0; j < srv->plugins.used; j++) { \
450 if (slot[j]) continue;\
451 slot[j] = p;\
452 break;\
457 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean);
458 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw);
459 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done);
460 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close);
461 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger);
462 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup);
463 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST, handle_subrequest);
464 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST_START, handle_subrequest_start);
465 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot);
466 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical);
467 PLUGIN_TO_SLOT(PLUGIN_FUNC_CONNECTION_RESET, connection_reset);
468 PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup);
469 PLUGIN_TO_SLOT(PLUGIN_FUNC_SET_DEFAULTS, set_defaults);
470 #undef PLUGIN_TO_SLOT
472 if (p->init) {
473 if (NULL == (p->data = p->init())) {
474 log_error_write(srv, __FILE__, __LINE__, "sb",
475 "plugin-init failed for module", p->name);
476 return HANDLER_ERROR;
479 /* used for con->mode, DIRECT == 0, plugins above that */
480 ((plugin_data *)(p->data))->id = i + 1;
482 if (p->version != LIGHTTPD_VERSION_ID) {
483 log_error_write(srv, __FILE__, __LINE__, "sb",
484 "plugin-version doesn't match lighttpd-version for", p->name);
485 return HANDLER_ERROR;
487 } else {
488 p->data = NULL;
492 return HANDLER_GO_ON;
495 void plugins_free(server *srv) {
496 size_t i;
497 plugins_call_cleanup(srv);
499 for (i = 0; i < srv->plugins.used; i++) {
500 plugin *p = ((plugin **)srv->plugins.ptr)[i];
502 plugin_free(p);
505 for (i = 0; srv->plugin_slots && i < PLUGIN_FUNC_SIZEOF; i++) {
506 plugin **slot = ((plugin ***)(srv->plugin_slots))[i];
508 if (slot) free(slot);
511 free(srv->plugin_slots);
512 srv->plugin_slots = NULL;
514 free(srv->plugins.ptr);
515 srv->plugins.ptr = NULL;
516 srv->plugins.used = 0;