File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / lighttpd / src / plugin.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 10:35:00 2016 UTC (7 years, 7 months ago) by misho
Branches: lighttpd, MAIN
CVS tags: v1_4_41p8, HEAD
lighttpd 1.4.41

    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>