9 #ifdef HAVE_VALGRIND_VALGRIND_H
10 # include <valgrind/valgrind.h>
13 #if !defined(__WIN32) && !defined(LIGHTTPD_STATIC)
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()
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
,
51 PLUGIN_FUNC_SET_DEFAULTS
,
56 static plugin
*plugin_init(void) {
59 p
= calloc(1, sizeof(*p
));
60 force_assert(NULL
!= p
);
65 static void plugin_free(plugin
*p
) {
66 #if !defined(LIGHTTPD_STATIC)
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;*/
75 #if !defined(LIGHTTPD_STATIC)
76 if (use_dlclose
&& p
->lib
) {
78 ) FreeLibrary(p
->lib
);
88 static int plugins_register(server
*srv
, plugin
*p
) {
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
;
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"
123 /* build NULL-terminated table of name + init-function */
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"
140 int plugins_load(server
*srv
) {
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)");
157 for (j
= 0; load_functions
[j
].name
; ++j
) {
158 if (0 == strcmp(load_functions
[j
].name
, module
)) {
160 if ((*load_functions
[j
].plugin_init
)(p
)) {
161 log_error_write(srv
, __FILE__
, __LINE__
, "ss", module
, "plugin init failed" );
165 plugins_register(srv
, p
);
169 if (!load_functions
[j
].name
) {
170 log_error_write(srv
, __FILE__
, __LINE__
, "ss", module
, " plugin not found" );
177 #else /* defined(LIGHTTPD_STATIC) */
178 int plugins_load(server
*srv
) {
180 int (*init
)(plugin
*pl
);
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)");
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"));
203 buffer_append_string_len(srv
->tmp_buf
, CONST_STR_LEN(".so"));
208 if (NULL
== (p
->lib
= LoadLibrary(srv
->tmp_buf
->ptr
))) {
211 FORMAT_MESSAGE_ALLOCATE_BUFFER
|
212 FORMAT_MESSAGE_FROM_SYSTEM
,
215 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
219 log_error_write(srv
, __FILE__
, __LINE__
, "ssb", "LoadLibrary() failed",
220 lpMsgBuf
, srv
->tmp_buf
);
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());
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"));
243 init
= GetProcAddress(p
->lib
, srv
->tmp_buf
->ptr
);
248 FORMAT_MESSAGE_ALLOCATE_BUFFER
|
249 FORMAT_MESSAGE_FROM_SYSTEM
,
252 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
256 log_error_write(srv
, __FILE__
, __LINE__
, "sbs", "getprocaddress failed:", srv
->tmp_buf
, lpMsgBuf
);
264 init
= (int (*)(plugin
*))(intptr_t)dlsym(p
->lib
, srv
->tmp_buf
->ptr
);
266 *(void **)(&init
) = dlsym(p
->lib
, srv
->tmp_buf
->ptr
);
269 const char *error
= dlerror();
271 log_error_write(srv
, __FILE__
, __LINE__
, "ss", "dlsym:", error
);
273 log_error_write(srv
, __FILE__
, __LINE__
, "ss", "dlsym symbol not found:", srv
->tmp_buf
->ptr
);
282 log_error_write(srv
, __FILE__
, __LINE__
, "ss", module
, "plugin init failed" );
288 log_error_write(srv
, __FILE__
, __LINE__
, "ss", module
, "plugin loaded" );
290 plugins_register(srv
, p
);
295 #endif /* defined(LIGHTTPD_STATIC) */
297 #define PLUGIN_TO_SLOT(x, y) \
298 handler_t plugins_call_##y(server *srv, connection *con) {\
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];\
306 switch(r = p->y(srv, con, p->data)) {\
309 case HANDLER_FINISHED:\
310 case HANDLER_COMEBACK:\
311 case HANDLER_WAIT_FOR_EVENT:\
312 case HANDLER_WAIT_FOR_FD:\
316 log_error_write(srv, __FILE__, __LINE__, "sbs", #x, p->name, "unknown state");\
317 return HANDLER_ERROR;\
320 return HANDLER_GO_ON;\
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) {\
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];\
357 switch(r = p->y(srv, p->data)) {\
360 case HANDLER_FINISHED:\
361 case HANDLER_COMEBACK:\
362 case HANDLER_WAIT_FOR_EVENT:\
363 case HANDLER_WAIT_FOR_FD:\
367 log_error_write(srv, __FILE__, __LINE__, "sbsd", #x, p->name, "unknown state:", r);\
368 return HANDLER_ERROR;\
371 return HANDLER_GO_ON;\
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
) {
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
;
406 handler_t
plugins_call_handle_fdevent(server
*srv
, const fd_conn
*fdc
) {
410 ps
= srv
->plugins
.ptr
;
412 for (i
= 0; i
< srv
->plugins
.used
; i
++) {
414 if (p
->handle_fdevent
) {
416 switch(r
= p
->handle_fdevent(srv
, fdc
, p
->data
)) {
419 case HANDLER_FINISHED
:
420 case HANDLER_COMEBACK
:
421 case HANDLER_WAIT_FOR_EVENT
:
425 log_error_write(srv
, __FILE__
, __LINE__
, "d", r
);
431 return HANDLER_GO_ON
;
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
) {
446 ps
= srv
->plugins
.ptr
;
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
++) {
455 /* check which calls are supported */
459 #define PLUGIN_TO_SLOT(x, y) \
461 plugin **slot = ((plugin ***)(srv->plugin_slots))[x]; \
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;\
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
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
;
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
) {
524 plugins_call_cleanup(srv
);
526 for (i
= 0; i
< srv
->plugins
.used
; i
++) {
527 plugin
*p
= ((plugin
**)srv
->plugins
.ptr
)[i
];
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;