Annotation of embedaddon/lighttpd/src/plugin.c, revision 1.1.1.2
1.1.1.2 ! misho 1: #include "first.h"
! 2:
1.1 misho 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:
1.1.1.2 ! misho 15: #if !defined(__WIN32) && !defined(LIGHTTPD_STATIC)
1.1 misho 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:
1.1.1.2 ! misho 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
1.1 misho 51: } plugin_t;
52:
53: static plugin *plugin_init(void) {
54: plugin *p;
55:
56: p = calloc(1, sizeof(*p));
1.1.1.2 ! misho 57: force_assert(NULL != p);
1.1 misho 58:
59: return p;
60: }
61:
62: static void plugin_free(plugin *p) {
1.1.1.2 ! misho 63: #if !defined(LIGHTTPD_STATIC)
1.1 misho 64: int use_dlclose = 1;
1.1.1.2 ! misho 65: #endif
! 66:
1.1 misho 67: if (p->name) buffer_free(p->name);
1.1.1.2 ! misho 68: #if defined(HAVE_VALGRIND_VALGRIND_H) && !defined(LIGHTTPD_STATIC)
1.1 misho 69: /*if (RUNNING_ON_VALGRIND) use_dlclose = 0;*/
70: #endif
71:
1.1.1.2 ! misho 72: #if !defined(LIGHTTPD_STATIC)
1.1 misho 73: if (use_dlclose && p->lib) {
1.1.1.2 ! misho 74: #if defined(__WIN32)
! 75: ) FreeLibrary(p->lib);
1.1 misho 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));
1.1.1.2 ! misho 90: force_assert(NULL != srv->plugins.ptr);
1.1 misho 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));
1.1.1.2 ! misho 95: force_assert(NULL != srv->plugins.ptr);
1.1 misho 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:
1.1.1.2 ! misho 110: #if defined(LIGHTTPD_STATIC)
! 111:
! 112: /* pre-declare functions, as there is no header for them */
1.1 misho 113: #define PLUGIN_INIT(x)\
1.1.1.2 ! misho 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 },
1.1 misho 130:
131: #include "plugin-static.h"
132:
1.1.1.2 ! misho 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:
1.1 misho 172: return 0;
173: }
1.1.1.2 ! misho 174: #else /* defined(LIGHTTPD_STATIC) */
1.1 misho 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];
1.1.1.2 ! misho 182: char *module = d->value->ptr;
1.1 misho 183:
184: for (j = 0; j < i; j++) {
185: if (buffer_is_equal(d->value, ((data_string *) srv->srvconf.modules->data[j])->value)) {
1.1.1.2 ! misho 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)");
1.1 misho 189: continue;
190: }
191: }
192:
1.1.1.2 ! misho 193: buffer_copy_buffer(srv->tmp_buf, srv->srvconf.modules_dir);
1.1 misho 194:
195: buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("/"));
1.1.1.2 ! misho 196: buffer_append_string(srv->tmp_buf, module);
1.1 misho 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(
1.1.1.2 ! misho 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);
1.1 misho 215:
216: log_error_write(srv, __FILE__, __LINE__, "ssb", "LoadLibrary() failed",
1.1.1.2 ! misho 217: lpMsgBuf, srv->tmp_buf);
1.1 misho 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:",
1.1.1.2 ! misho 227: srv->tmp_buf, dlerror());
1.1 misho 228:
229: plugin_free(p);
230:
231: return -1;
232: }
233:
234: #endif
235: buffer_reset(srv->tmp_buf);
1.1.1.2 ! misho 236: buffer_copy_string(srv->tmp_buf, module);
1.1 misho 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:
1.1.1.2 ! misho 242: if (init == NULL) {
1.1 misho 243: LPVOID lpMsgBuf;
244: FormatMessage(
1.1.1.2 ! misho 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);
1.1 misho 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
1.1.1.2 ! misho 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: }
1.1 misho 272:
273: plugin_free(p);
274: return -1;
275: }
276:
277: #endif
278: if ((*init)(p)) {
1.1.1.2 ! misho 279: log_error_write(srv, __FILE__, __LINE__, "ss", module, "plugin init failed" );
1.1 misho 280:
281: plugin_free(p);
282: return -1;
283: }
284: #if 0
1.1.1.2 ! misho 285: log_error_write(srv, __FILE__, __LINE__, "ss", module, "plugin loaded" );
1.1 misho 286: #endif
287: plugins_register(srv, p);
288: }
289:
290: return 0;
291: }
1.1.1.2 ! misho 292: #endif /* defined(LIGHTTPD_STATIC) */
1.1 misho 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;\
1.1.1.2 ! misho 298: if (!srv->plugin_slots) return HANDLER_GO_ON;\
! 299: slot = ((plugin ***)(srv->plugin_slots))[x];\
1.1 misho 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;\
1.1.1.2 ! misho 345: if (!srv->plugin_slots) return HANDLER_GO_ON;\
! 346: slot = ((plugin ***)(srv->plugin_slots))[x];\
1.1 misho 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));
1.1.1.2 ! misho 433: force_assert(NULL != srv->plugin_slots);
1.1 misho 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));\
1.1.1.2 ! misho 446: force_assert(NULL != slot); \
1.1 misho 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>