1: #include "first.h"
2:
3: #include "plugin.h"
4: #include "log.h"
5:
6: #include <string.h>
7: #include <stdlib.h>
8:
9: #include <stdio.h>
10:
11: #ifdef HAVE_VALGRIND_VALGRIND_H
12: # include <valgrind/valgrind.h>
13: #endif
14:
15: #if !defined(__WIN32) && !defined(LIGHTTPD_STATIC)
16: # include <dlfcn.h>
17: #endif
18: /*
19: *
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()
25: *
26: */
27:
28: typedef struct {
29: PLUGIN_DATA;
30: } plugin_data;
31:
32: typedef enum {
33: PLUGIN_FUNC_UNSET,
34:
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,
49:
50: PLUGIN_FUNC_SIZEOF
51: } plugin_t;
52:
53: static plugin *plugin_init(void) {
54: plugin *p;
55:
56: p = calloc(1, sizeof(*p));
57: force_assert(NULL != p);
58:
59: return p;
60: }
61:
62: static void plugin_free(plugin *p) {
63: #if !defined(LIGHTTPD_STATIC)
64: int use_dlclose = 1;
65: #endif
66:
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
71:
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
79: }
80: #endif
81:
82: free(p);
83: }
84:
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);
96: }
97:
98: ps = srv->plugins.ptr;
99: ps[srv->plugins.used++] = p;
100:
101: return 0;
102: }
103:
104: /**
105: *
106: *
107: *
108: */
109:
110: #if defined(LIGHTTPD_STATIC)
111:
112: /* pre-declare functions, as there is no header for them */
113: #define PLUGIN_INIT(x)\
114: int x ## _plugin_init(plugin *p);
115:
116: #include "plugin-static.h"
117:
118: #undef PLUGIN_INIT
119:
120: /* build NULL-terminated table of name + init-function */
121:
122: typedef struct {
123: const char* name;
124: int (*plugin_init)(plugin *p);
125: } plugin_load_functions;
126:
127: static const plugin_load_functions load_functions[] = {
128: #define PLUGIN_INIT(x) \
129: { #x, &x ## _plugin_init },
130:
131: #include "plugin-static.h"
132:
133: { NULL, NULL }
134: #undef PLUGIN_INIT
135: };
136:
137: int plugins_load(server *srv) {
138: plugin *p;
139: size_t i, j;
140:
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;
144:
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;
151: }
152: }
153:
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;
161: }
162: plugins_register(srv, p);
163: break;
164: }
165: }
166: if (!load_functions[j].name) {
167: log_error_write(srv, __FILE__, __LINE__, "ss", module, " plugin not found" );
168: return -1;
169: }
170: }
171:
172: return 0;
173: }
174: #else /* defined(LIGHTTPD_STATIC) */
175: int plugins_load(server *srv) {
176: plugin *p;
177: int (*init)(plugin *pl);
178: size_t i, j;
179:
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;
183:
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;
190: }
191: }
192:
193: buffer_copy_buffer(srv->tmp_buf, srv->srvconf.modules_dir);
194:
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
202:
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);
215:
216: log_error_write(srv, __FILE__, __LINE__, "ssb", "LoadLibrary() failed",
217: lpMsgBuf, srv->tmp_buf);
218:
219: plugin_free(p);
220:
221: return -1;
222:
223: }
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());
228:
229: plugin_free(p);
230:
231: return -1;
232: }
233:
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"));
238:
239: #ifdef __WIN32
240: init = GetProcAddress(p->lib, srv->tmp_buf->ptr);
241:
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);
252:
253: log_error_write(srv, __FILE__, __LINE__, "sbs", "getprocaddress failed:", srv->tmp_buf, lpMsgBuf);
254:
255: plugin_free(p);
256: return -1;
257: }
258:
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);
271: }
272:
273: plugin_free(p);
274: return -1;
275: }
276:
277: #endif
278: if ((*init)(p)) {
279: log_error_write(srv, __FILE__, __LINE__, "ss", module, "plugin init failed" );
280:
281: plugin_free(p);
282: return -1;
283: }
284: #if 0
285: log_error_write(srv, __FILE__, __LINE__, "ss", module, "plugin loaded" );
286: #endif
287: plugins_register(srv, p);
288: }
289:
290: return 0;
291: }
292: #endif /* defined(LIGHTTPD_STATIC) */
293:
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;\
316: }\
317: }\
318: return HANDLER_GO_ON;\
319: }
320:
321: /**
322: * plugins that use
323: *
324: * - server *srv
325: * - connection *con
326: * - void *p_d (plugin_data *)
327: */
328:
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)
338:
339: #undef PLUGIN_TO_SLOT
340:
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;\
363: }\
364: }\
365: return HANDLER_GO_ON;\
366: }
367:
368: /**
369: * plugins that use
370: *
371: * - server *srv
372: * - void *p_d (plugin_data *)
373: */
374:
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)
379:
380: #undef PLUGIN_TO_SLOT
381:
382: #if 0
383: /**
384: *
385: * special handler
386: *
387: */
388: handler_t plugins_call_handle_fdevent(server *srv, const fd_conn *fdc) {
389: size_t i;
390: plugin **ps;
391:
392: ps = srv->plugins.ptr;
393:
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;
409: }
410: }
411: }
412:
413: return HANDLER_GO_ON;
414: }
415: #endif
416: /**
417: *
418: * - call init function of all plugins to init the plugin-internals
419: * - added each plugin that supports has callback to the corresponding slot
420: *
421: * - is only called once.
422: */
423:
424: handler_t plugins_call_init(server *srv) {
425: size_t i;
426: plugin **ps;
427:
428: ps = srv->plugins.ptr;
429:
430: /* fill slots */
431:
432: srv->plugin_slots = calloc(PLUGIN_FUNC_SIZEOF, sizeof(ps));
433: force_assert(NULL != srv->plugin_slots);
434:
435: for (i = 0; i < srv->plugins.used; i++) {
436: size_t j;
437: /* check which calls are supported */
438:
439: plugin *p = ps[i];
440:
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; \
448: } \
449: for (j = 0; j < srv->plugins.used; j++) { \
450: if (slot[j]) continue;\
451: slot[j] = p;\
452: break;\
453: }\
454: }
455:
456:
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
471:
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;
477: }
478:
479: /* used for con->mode, DIRECT == 0, plugins above that */
480: ((plugin_data *)(p->data))->id = i + 1;
481:
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;
486: }
487: } else {
488: p->data = NULL;
489: }
490: }
491:
492: return HANDLER_GO_ON;
493: }
494:
495: void plugins_free(server *srv) {
496: size_t i;
497: plugins_call_cleanup(srv);
498:
499: for (i = 0; i < srv->plugins.used; i++) {
500: plugin *p = ((plugin **)srv->plugins.ptr)[i];
501:
502: plugin_free(p);
503: }
504:
505: for (i = 0; srv->plugin_slots && i < PLUGIN_FUNC_SIZEOF; i++) {
506: plugin **slot = ((plugin ***)(srv->plugin_slots))[i];
507:
508: if (slot) free(slot);
509: }
510:
511: free(srv->plugin_slots);
512: srv->plugin_slots = NULL;
513:
514: free(srv->plugins.ptr);
515: srv->plugins.ptr = NULL;
516: srv->plugins.used = 0;
517: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>