File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / lighttpd / src / plugin.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Oct 14 10:32:48 2013 UTC (10 years, 8 months ago) by misho
Branches: lighttpd, MAIN
CVS tags: v1_4_35p0, v1_4_35, v1_4_33, HEAD
1.4.33

    1: #include "plugin.h"
    2: #include "log.h"
    3: 
    4: #include <string.h>
    5: #include <stdlib.h>
    6: 
    7: #include <stdio.h>
    8: 
    9: #ifdef HAVE_VALGRIND_VALGRIND_H
   10: # include <valgrind/valgrind.h>
   11: #endif
   12: 
   13: #ifndef __WIN32
   14: # include <dlfcn.h>
   15: #endif
   16: /*
   17:  *
   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()
   23:  *
   24:  */
   25: 
   26: typedef struct {
   27: 	PLUGIN_DATA;
   28: } plugin_data;
   29: 
   30: typedef enum {
   31: 	PLUGIN_FUNC_UNSET,
   32: 		PLUGIN_FUNC_HANDLE_URI_CLEAN,
   33: 		PLUGIN_FUNC_HANDLE_URI_RAW,
   34: 		PLUGIN_FUNC_HANDLE_REQUEST_DONE,
   35: 		PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE,
   36: 		PLUGIN_FUNC_HANDLE_TRIGGER,
   37: 		PLUGIN_FUNC_HANDLE_SIGHUP,
   38: 		PLUGIN_FUNC_HANDLE_SUBREQUEST,
   39: 		PLUGIN_FUNC_HANDLE_SUBREQUEST_START,
   40: 		PLUGIN_FUNC_HANDLE_JOBLIST,
   41: 		PLUGIN_FUNC_HANDLE_DOCROOT,
   42: 		PLUGIN_FUNC_HANDLE_PHYSICAL,
   43: 		PLUGIN_FUNC_CONNECTION_RESET,
   44: 		PLUGIN_FUNC_INIT,
   45: 		PLUGIN_FUNC_CLEANUP,
   46: 		PLUGIN_FUNC_SET_DEFAULTS,
   47: 
   48: 		PLUGIN_FUNC_SIZEOF
   49: } plugin_t;
   50: 
   51: static plugin *plugin_init(void) {
   52: 	plugin *p;
   53: 
   54: 	p = calloc(1, sizeof(*p));
   55: 
   56: 	return p;
   57: }
   58: 
   59: static void plugin_free(plugin *p) {
   60: 	int use_dlclose = 1;
   61: 	if (p->name) buffer_free(p->name);
   62: #ifdef HAVE_VALGRIND_VALGRIND_H
   63: 	/*if (RUNNING_ON_VALGRIND) use_dlclose = 0;*/
   64: #endif
   65: 
   66: #ifndef LIGHTTPD_STATIC
   67: 	if (use_dlclose && p->lib) {
   68: #ifdef __WIN32
   69: 		FreeLibrary(p->lib);
   70: #else
   71: 		dlclose(p->lib);
   72: #endif
   73: 	}
   74: #endif
   75: 
   76: 	free(p);
   77: }
   78: 
   79: static int plugins_register(server *srv, plugin *p) {
   80: 	plugin **ps;
   81: 	if (0 == srv->plugins.size) {
   82: 		srv->plugins.size = 4;
   83: 		srv->plugins.ptr  = malloc(srv->plugins.size * sizeof(*ps));
   84: 		srv->plugins.used = 0;
   85: 	} else if (srv->plugins.used == srv->plugins.size) {
   86: 		srv->plugins.size += 4;
   87: 		srv->plugins.ptr   = realloc(srv->plugins.ptr, srv->plugins.size * sizeof(*ps));
   88: 	}
   89: 
   90: 	ps = srv->plugins.ptr;
   91: 	ps[srv->plugins.used++] = p;
   92: 
   93: 	return 0;
   94: }
   95: 
   96: /**
   97:  *
   98:  *
   99:  *
  100:  */
  101: 
  102: #ifdef LIGHTTPD_STATIC
  103: int plugins_load(server *srv) {
  104: 	plugin *p;
  105: #define PLUGIN_INIT(x)\
  106: 	p = plugin_init(); \
  107: 	if (x ## _plugin_init(p)) { \
  108: 		log_error_write(srv, __FILE__, __LINE__, "ss", #x, "plugin init failed" ); \
  109: 		plugin_free(p); \
  110: 		return -1;\
  111: 	}\
  112: 	plugins_register(srv, p);
  113: 
  114: #include "plugin-static.h"
  115: 
  116: 	return 0;
  117: }
  118: #else
  119: int plugins_load(server *srv) {
  120: 	plugin *p;
  121: 	int (*init)(plugin *pl);
  122: 	const char *error;
  123: 	size_t i, j;
  124: 
  125: 	for (i = 0; i < srv->srvconf.modules->used; i++) {
  126: 		data_string *d = (data_string *)srv->srvconf.modules->data[i];
  127: 		char *modules = d->value->ptr;
  128: 
  129: 		for (j = 0; j < i; j++) {
  130: 			if (buffer_is_equal(d->value, ((data_string *) srv->srvconf.modules->data[j])->value)) {
  131: 				log_error_write(srv, __FILE__, __LINE__, "sbs", "Cannot load plugin", d->value, "more than once, please fix your config (we may not accept such configs in future releases");
  132: 				continue;
  133: 			}
  134: 		}
  135: 
  136: 		buffer_copy_string_buffer(srv->tmp_buf, srv->srvconf.modules_dir);
  137: 
  138: 		buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("/"));
  139: 		buffer_append_string(srv->tmp_buf, modules);
  140: #if defined(__WIN32) || defined(__CYGWIN__)
  141: 		buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN(".dll"));
  142: #else
  143: 		buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN(".so"));
  144: #endif
  145: 
  146: 		p = plugin_init();
  147: #ifdef __WIN32
  148: 		if (NULL == (p->lib = LoadLibrary(srv->tmp_buf->ptr))) {
  149: 			LPVOID lpMsgBuf;
  150: 			FormatMessage(
  151: 		        	FORMAT_MESSAGE_ALLOCATE_BUFFER |
  152: 		       		FORMAT_MESSAGE_FROM_SYSTEM,
  153: 		        	NULL,
  154: 		        	GetLastError(),
  155: 		        	MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  156: 		        	(LPTSTR) &lpMsgBuf,
  157: 		        	0, NULL );
  158: 
  159: 			log_error_write(srv, __FILE__, __LINE__, "ssb", "LoadLibrary() failed",
  160: 					lpMsgBuf, srv->tmp_buf);
  161: 
  162: 			plugin_free(p);
  163: 
  164: 			return -1;
  165: 
  166: 		}
  167: #else
  168: 		if (NULL == (p->lib = dlopen(srv->tmp_buf->ptr, RTLD_NOW|RTLD_GLOBAL))) {
  169: 			log_error_write(srv, __FILE__, __LINE__, "sbs", "dlopen() failed for:",
  170: 					srv->tmp_buf, dlerror());
  171: 
  172: 			plugin_free(p);
  173: 
  174: 			return -1;
  175: 		}
  176: 
  177: #endif
  178: 		buffer_reset(srv->tmp_buf);
  179: 		buffer_copy_string(srv->tmp_buf, modules);
  180: 		buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("_plugin_init"));
  181: 
  182: #ifdef __WIN32
  183: 		init = GetProcAddress(p->lib, srv->tmp_buf->ptr);
  184: 
  185: 		if (init == NULL)  {
  186: 			LPVOID lpMsgBuf;
  187: 			FormatMessage(
  188: 		        	FORMAT_MESSAGE_ALLOCATE_BUFFER |
  189: 		       		FORMAT_MESSAGE_FROM_SYSTEM,
  190: 		        	NULL,
  191: 		        	GetLastError(),
  192: 		        	MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  193: 		        	(LPTSTR) &lpMsgBuf,
  194: 		        	0, NULL );
  195: 
  196: 			log_error_write(srv, __FILE__, __LINE__, "sbs", "getprocaddress failed:", srv->tmp_buf, lpMsgBuf);
  197: 
  198: 			plugin_free(p);
  199: 			return -1;
  200: 		}
  201: 
  202: #else
  203: #if 1
  204: 		init = (int (*)(plugin *))(intptr_t)dlsym(p->lib, srv->tmp_buf->ptr);
  205: #else
  206: 		*(void **)(&init) = dlsym(p->lib, srv->tmp_buf->ptr);
  207: #endif
  208: 		if ((error = dlerror()) != NULL)  {
  209: 			log_error_write(srv, __FILE__, __LINE__, "s", error);
  210: 
  211: 			plugin_free(p);
  212: 			return -1;
  213: 		}
  214: 
  215: #endif
  216: 		if ((*init)(p)) {
  217: 			log_error_write(srv, __FILE__, __LINE__, "ss", modules, "plugin init failed" );
  218: 
  219: 			plugin_free(p);
  220: 			return -1;
  221: 		}
  222: #if 0
  223: 		log_error_write(srv, __FILE__, __LINE__, "ss", modules, "plugin loaded" );
  224: #endif
  225: 		plugins_register(srv, p);
  226: 	}
  227: 
  228: 	return 0;
  229: }
  230: #endif
  231: 
  232: #define PLUGIN_TO_SLOT(x, y) \
  233: 	handler_t plugins_call_##y(server *srv, connection *con) {\
  234: 		plugin **slot;\
  235: 		size_t j;\
  236:                 if (!srv->plugin_slots) return HANDLER_GO_ON;\
  237:                 slot = ((plugin ***)(srv->plugin_slots))[x];\
  238: 		if (!slot) return HANDLER_GO_ON;\
  239: 		for (j = 0; j < srv->plugins.used && slot[j]; j++) { \
  240: 			plugin *p = slot[j];\
  241: 			handler_t r;\
  242: 			switch(r = p->y(srv, con, p->data)) {\
  243: 			case HANDLER_GO_ON:\
  244: 				break;\
  245: 			case HANDLER_FINISHED:\
  246: 			case HANDLER_COMEBACK:\
  247: 			case HANDLER_WAIT_FOR_EVENT:\
  248: 			case HANDLER_WAIT_FOR_FD:\
  249: 			case HANDLER_ERROR:\
  250: 				return r;\
  251: 			default:\
  252: 				log_error_write(srv, __FILE__, __LINE__, "sbs", #x, p->name, "unknown state");\
  253: 				return HANDLER_ERROR;\
  254: 			}\
  255: 		}\
  256: 		return HANDLER_GO_ON;\
  257: 	}
  258: 
  259: /**
  260:  * plugins that use
  261:  *
  262:  * - server *srv
  263:  * - connection *con
  264:  * - void *p_d (plugin_data *)
  265:  */
  266: 
  267: PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean)
  268: PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw)
  269: PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done)
  270: PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close)
  271: PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST, handle_subrequest)
  272: PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST_START, handle_subrequest_start)
  273: PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_JOBLIST, handle_joblist)
  274: PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot)
  275: PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical)
  276: PLUGIN_TO_SLOT(PLUGIN_FUNC_CONNECTION_RESET, connection_reset)
  277: 
  278: #undef PLUGIN_TO_SLOT
  279: 
  280: #define PLUGIN_TO_SLOT(x, y) \
  281: 	handler_t plugins_call_##y(server *srv) {\
  282: 		plugin **slot;\
  283: 		size_t j;\
  284:                 if (!srv->plugin_slots) return HANDLER_GO_ON;\
  285:                 slot = ((plugin ***)(srv->plugin_slots))[x];\
  286: 		if (!slot) return HANDLER_GO_ON;\
  287: 		for (j = 0; j < srv->plugins.used && slot[j]; j++) { \
  288: 			plugin *p = slot[j];\
  289: 			handler_t r;\
  290: 			switch(r = p->y(srv, p->data)) {\
  291: 			case HANDLER_GO_ON:\
  292: 				break;\
  293: 			case HANDLER_FINISHED:\
  294: 			case HANDLER_COMEBACK:\
  295: 			case HANDLER_WAIT_FOR_EVENT:\
  296: 			case HANDLER_WAIT_FOR_FD:\
  297: 			case HANDLER_ERROR:\
  298: 				return r;\
  299: 			default:\
  300: 				log_error_write(srv, __FILE__, __LINE__, "sbsd", #x, p->name, "unknown state:", r);\
  301: 				return HANDLER_ERROR;\
  302: 			}\
  303: 		}\
  304: 		return HANDLER_GO_ON;\
  305: 	}
  306: 
  307: /**
  308:  * plugins that use
  309:  *
  310:  * - server *srv
  311:  * - void *p_d (plugin_data *)
  312:  */
  313: 
  314: PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger)
  315: PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup)
  316: PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup)
  317: PLUGIN_TO_SLOT(PLUGIN_FUNC_SET_DEFAULTS, set_defaults)
  318: 
  319: #undef PLUGIN_TO_SLOT
  320: 
  321: #if 0
  322: /**
  323:  *
  324:  * special handler
  325:  *
  326:  */
  327: handler_t plugins_call_handle_fdevent(server *srv, const fd_conn *fdc) {
  328: 	size_t i;
  329: 	plugin **ps;
  330: 
  331: 	ps = srv->plugins.ptr;
  332: 
  333: 	for (i = 0; i < srv->plugins.used; i++) {
  334: 		plugin *p = ps[i];
  335: 		if (p->handle_fdevent) {
  336: 			handler_t r;
  337: 			switch(r = p->handle_fdevent(srv, fdc, p->data)) {
  338: 			case HANDLER_GO_ON:
  339: 				break;
  340: 			case HANDLER_FINISHED:
  341: 			case HANDLER_COMEBACK:
  342: 			case HANDLER_WAIT_FOR_EVENT:
  343: 			case HANDLER_ERROR:
  344: 				return r;
  345: 			default:
  346: 				log_error_write(srv, __FILE__, __LINE__, "d", r);
  347: 				break;
  348: 			}
  349: 		}
  350: 	}
  351: 
  352: 	return HANDLER_GO_ON;
  353: }
  354: #endif
  355: /**
  356:  *
  357:  * - call init function of all plugins to init the plugin-internals
  358:  * - added each plugin that supports has callback to the corresponding slot
  359:  *
  360:  * - is only called once.
  361:  */
  362: 
  363: handler_t plugins_call_init(server *srv) {
  364: 	size_t i;
  365: 	plugin **ps;
  366: 
  367: 	ps = srv->plugins.ptr;
  368: 
  369: 	/* fill slots */
  370: 
  371: 	srv->plugin_slots = calloc(PLUGIN_FUNC_SIZEOF, sizeof(ps));
  372: 
  373: 	for (i = 0; i < srv->plugins.used; i++) {
  374: 		size_t j;
  375: 		/* check which calls are supported */
  376: 
  377: 		plugin *p = ps[i];
  378: 
  379: #define PLUGIN_TO_SLOT(x, y) \
  380: 	if (p->y) { \
  381: 		plugin **slot = ((plugin ***)(srv->plugin_slots))[x]; \
  382: 		if (!slot) { \
  383: 			slot = calloc(srv->plugins.used, sizeof(*slot));\
  384: 			((plugin ***)(srv->plugin_slots))[x] = slot; \
  385: 		} \
  386: 		for (j = 0; j < srv->plugins.used; j++) { \
  387: 			if (slot[j]) continue;\
  388: 			slot[j] = p;\
  389: 			break;\
  390: 		}\
  391: 	}
  392: 
  393: 
  394: 		PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean);
  395: 		PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw);
  396: 		PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done);
  397: 		PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close);
  398: 		PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger);
  399: 		PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup);
  400: 		PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST, handle_subrequest);
  401: 		PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST_START, handle_subrequest_start);
  402: 		PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_JOBLIST, handle_joblist);
  403: 		PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot);
  404: 		PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical);
  405: 		PLUGIN_TO_SLOT(PLUGIN_FUNC_CONNECTION_RESET, connection_reset);
  406: 		PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup);
  407: 		PLUGIN_TO_SLOT(PLUGIN_FUNC_SET_DEFAULTS, set_defaults);
  408: #undef PLUGIN_TO_SLOT
  409: 
  410: 		if (p->init) {
  411: 			if (NULL == (p->data = p->init())) {
  412: 				log_error_write(srv, __FILE__, __LINE__, "sb",
  413: 						"plugin-init failed for module", p->name);
  414: 				return HANDLER_ERROR;
  415: 			}
  416: 
  417: 			/* used for con->mode, DIRECT == 0, plugins above that */
  418: 			((plugin_data *)(p->data))->id = i + 1;
  419: 
  420: 			if (p->version != LIGHTTPD_VERSION_ID) {
  421: 				log_error_write(srv, __FILE__, __LINE__, "sb",
  422: 						"plugin-version doesn't match lighttpd-version for", p->name);
  423: 				return HANDLER_ERROR;
  424: 			}
  425: 		} else {
  426: 			p->data = NULL;
  427: 		}
  428: 	}
  429: 
  430: 	return HANDLER_GO_ON;
  431: }
  432: 
  433: void plugins_free(server *srv) {
  434: 	size_t i;
  435: 	plugins_call_cleanup(srv);
  436: 
  437: 	for (i = 0; i < srv->plugins.used; i++) {
  438: 		plugin *p = ((plugin **)srv->plugins.ptr)[i];
  439: 
  440: 		plugin_free(p);
  441: 	}
  442: 
  443: 	for (i = 0; srv->plugin_slots && i < PLUGIN_FUNC_SIZEOF; i++) {
  444: 		plugin **slot = ((plugin ***)(srv->plugin_slots))[i];
  445: 
  446: 		if (slot) free(slot);
  447: 	}
  448: 
  449: 	free(srv->plugin_slots);
  450: 	srv->plugin_slots = NULL;
  451: 
  452: 	free(srv->plugins.ptr);
  453: 	srv->plugins.ptr = NULL;
  454: 	srv->plugins.used = 0;
  455: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>