xref: /lighttpd1.4/src/plugin.c (revision d147673d)
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 }
518