xref: /lighttpd1.4/src/plugin.c (revision 94edf7e8)
1 #include "first.h"
2 
3 #include "plugin.h"
4 #include "base.h"
5 #include "array.h"
6 #include "log.h"
7 
8 #include <string.h>
9 #include <stdlib.h>
10 
11 array plugin_stats; /* global */
12 
13 #ifdef HAVE_VALGRIND_VALGRIND_H
14 # include <valgrind/valgrind.h>
15 #endif
16 
17 #ifndef LIGHTTPD_STATIC
18 #ifdef HAVE_DLFCN_H
19 #include <dlfcn.h>
20 #endif
21 #endif
22 /*
23  *
24  * if you change this enum to add a new callback, be sure
25  * - that PLUGIN_FUNC_SIZEOF is the last entry
26  * - that you add:
27  *   1. PLUGIN_CALL_... as callback-dispatcher
28  *   2. count and assignment in plugins_call_init()
29  *
30  */
31 
32 typedef enum {
33 	PLUGIN_FUNC_HANDLE_URI_CLEAN,
34 	PLUGIN_FUNC_HANDLE_DOCROOT,
35 	PLUGIN_FUNC_HANDLE_PHYSICAL,
36 	PLUGIN_FUNC_HANDLE_SUBREQUEST_START,
37 	/* PLUGIN_FUNC_HANDLE_SUBREQUEST, *//* max one handler_module per req */
38 	PLUGIN_FUNC_HANDLE_RESPONSE_START,
39 	PLUGIN_FUNC_HANDLE_REQUEST_DONE,
40 	PLUGIN_FUNC_HANDLE_REQUEST_RESET,
41 	PLUGIN_FUNC_HANDLE_REQUEST_ENV,
42 	PLUGIN_FUNC_HANDLE_CONNECTION_ACCEPT,
43 	PLUGIN_FUNC_HANDLE_CONNECTION_SHUT_WR,
44 	PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE,
45 	PLUGIN_FUNC_HANDLE_TRIGGER,
46 	PLUGIN_FUNC_HANDLE_WAITPID,
47 	PLUGIN_FUNC_HANDLE_SIGHUP,
48 	/* PLUGIN_FUNC_INIT, *//* handled here in plugin.c */
49 	/* PLUGIN_FUNC_CLEANUP, *//* handled here in plugin.c */
50 	PLUGIN_FUNC_SET_DEFAULTS,
51 	PLUGIN_FUNC_WORKER_INIT,
52 
53 	PLUGIN_FUNC_SIZEOF
54 } plugin_t;
55 
56 __attribute_malloc__
57 __attribute_returns_nonnull__
58 static plugin *plugin_init(void) {
59 	plugin *p;
60 
61 	p = calloc(1, sizeof(*p));
62 	force_assert(NULL != p);
63 
64 	return p;
65 }
66 
67 static void plugin_free(plugin *p) {
68     if (NULL == p) return; /*(should not happen w/ current usage)*/
69   #if !defined(LIGHTTPD_STATIC)
70     if (p->lib) {
71      #if defined(HAVE_VALGRIND_VALGRIND_H)
72      /*if (!RUNNING_ON_VALGRIND) */
73      #endif
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 void plugins_register(server *srv, plugin *p) {
86 	plugin **ps;
87 	if (srv->plugins.used == srv->plugins.size) {
88 		srv->plugins.size += 4;
89 		srv->plugins.ptr   = realloc(srv->plugins.ptr, srv->plugins.size * sizeof(*ps));
90 		force_assert(NULL != srv->plugins.ptr);
91 	}
92 
93 	ps = srv->plugins.ptr;
94 	ps[srv->plugins.used++] = p;
95 }
96 
97 /**
98  *
99  *
100  *
101  */
102 
103 #if defined(LIGHTTPD_STATIC)
104 
105 /* pre-declare functions, as there is no header for them */
106 #define PLUGIN_INIT(x)\
107 	int x ## _plugin_init(plugin *p);
108 
109 #include "plugin-static.h"
110 
111 #undef PLUGIN_INIT
112 
113 /* build NULL-terminated table of name + init-function */
114 
115 typedef struct {
116 	const char* name;
117 	int (*plugin_init)(plugin *p);
118 } plugin_load_functions;
119 
120 static const plugin_load_functions load_functions[] = {
121 #define PLUGIN_INIT(x) \
122 	{ #x, &x ## _plugin_init },
123 
124 #include "plugin-static.h"
125 
126 	{ NULL, NULL }
127 #undef PLUGIN_INIT
128 };
129 
130 int plugins_load(server *srv) {
131 	for (uint32_t i = 0; i < srv->srvconf.modules->used; ++i) {
132 		data_string *ds = (data_string *)srv->srvconf.modules->data[i];
133 		char *module = ds->value.ptr;
134 
135 		uint32_t j;
136 		for (j = 0; load_functions[j].name; ++j) {
137 			if (0 == strcmp(load_functions[j].name, module)) {
138 				plugin * const p = plugin_init();
139 				if ((*load_functions[j].plugin_init)(p)) {
140 					log_error(srv->errh, __FILE__, __LINE__, "%s plugin init failed", module);
141 					plugin_free(p);
142 					return -1;
143 				}
144 				plugins_register(srv, p);
145 				break;
146 			}
147 		}
148 		if (!load_functions[j].name) {
149 			log_error(srv->errh, __FILE__, __LINE__, "%s plugin not found", module);
150 			if (srv->srvconf.compat_module_load) {
151 				if (buffer_eq_slen(&ds->value, CONST_STR_LEN("mod_deflate")))
152 					continue;
153 			}
154 			return -1;
155 		}
156 	}
157 
158 	return 0;
159 }
160 #else /* defined(LIGHTTPD_STATIC) */
161 int plugins_load(server *srv) {
162 	buffer * const tb = srv->tmp_buf;
163 	plugin *p;
164 	int (*init)(plugin *pl);
165 
166 	for (uint32_t i = 0; i < srv->srvconf.modules->used; ++i) {
167 		const buffer * const module = &((data_string *)srv->srvconf.modules->data[i])->value;
168 		buffer_copy_path_len2(tb, BUF_PTR_LEN(srv->srvconf.modules_dir),
169 		                          BUF_PTR_LEN(module));
170 #if defined(__WIN32) || defined(__CYGWIN__)
171 		buffer_append_string_len(tb, CONST_STR_LEN(".dll"));
172 #else
173 		buffer_append_string_len(tb, CONST_STR_LEN(".so"));
174 #endif
175 
176 		p = plugin_init();
177 #ifdef __WIN32
178 		if (NULL == (p->lib = LoadLibrary(tb->ptr))) {
179 			LPVOID lpMsgBuf;
180 			FormatMessage(
181 				FORMAT_MESSAGE_ALLOCATE_BUFFER |
182 					FORMAT_MESSAGE_FROM_SYSTEM,
183 				NULL,
184 				GetLastError(),
185 				MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
186 				(LPTSTR) &lpMsgBuf,
187 				0, NULL);
188 
189 			log_error(srv->errh, __FILE__, __LINE__,
190 			  "LoadLibrary() failed %s %s", lpMsgBuf, tb->ptr);
191 
192 			plugin_free(p);
193 
194 			if (srv->srvconf.compat_module_load) {
195 				if (buffer_eq_slen(module, CONST_STR_LEN("mod_deflate")))
196 					continue;
197 			}
198 			return -1;
199 
200 		}
201 #else
202 		if (NULL == (p->lib = dlopen(tb->ptr, RTLD_NOW|RTLD_GLOBAL))) {
203 			log_error(srv->errh, __FILE__, __LINE__,
204 			  "dlopen() failed for: %s %s", tb->ptr, dlerror());
205 
206 			plugin_free(p);
207 
208 			if (srv->srvconf.compat_module_load) {
209 				if (buffer_eq_slen(module, CONST_STR_LEN("mod_deflate")))
210 					continue;
211 			}
212 			return -1;
213 		}
214 
215 #endif
216 		buffer_clear(tb);
217 		buffer_append_str2(tb, BUF_PTR_LEN(module),
218                                        CONST_STR_LEN("_plugin_init"));
219 
220 #ifdef __WIN32
221 		init = GetProcAddress(p->lib, tb->ptr);
222 
223 		if (init == NULL) {
224 			LPVOID lpMsgBuf;
225 			FormatMessage(
226 				FORMAT_MESSAGE_ALLOCATE_BUFFER |
227 					FORMAT_MESSAGE_FROM_SYSTEM,
228 				NULL,
229 				GetLastError(),
230 				MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
231 				(LPTSTR) &lpMsgBuf,
232 				0, NULL);
233 
234 			log_error(srv->errh, __FILE__, __LINE__,
235 			  "getprocaddress failed: %s %s", tb->ptr, lpMsgBuf);
236 
237 			plugin_free(p);
238 			return -1;
239 		}
240 
241 #else
242 #if 1
243 		init = (int (*)(plugin *))(intptr_t)dlsym(p->lib, tb->ptr);
244 #else
245 		*(void **)(&init) = dlsym(p->lib, tb->ptr);
246 #endif
247 		if (NULL == init) {
248 			const char *error = dlerror();
249 			if (error != NULL) {
250 				log_error(srv->errh, __FILE__, __LINE__, "dlsym: %s", error);
251 			} else {
252 				log_error(srv->errh, __FILE__, __LINE__, "dlsym symbol not found: %s", tb->ptr);
253 			}
254 
255 			plugin_free(p);
256 			return -1;
257 		}
258 
259 #endif
260 		if ((*init)(p)) {
261 			log_error(srv->errh, __FILE__, __LINE__, "%s plugin init failed", module->ptr);
262 
263 			plugin_free(p);
264 			return -1;
265 		}
266 #if 0
267 		log_error(srv->errh, __FILE__, __LINE__, "%s plugin loaded", module->ptr);
268 #endif
269 		plugins_register(srv, p);
270 	}
271 
272 	return 0;
273 }
274 #endif /* defined(LIGHTTPD_STATIC) */
275 
276 typedef struct {
277   handler_t(*fn)();
278   plugin_data_base *data;
279 } plugin_fn_data;
280 
281 __attribute_hot__
282 static handler_t plugins_call_fn_req_data(request_st * const r, const int e) {
283     const void * const plugin_slots = r->con->plugin_slots;
284     const uint32_t offset = ((const uint16_t *)plugin_slots)[e];
285     if (0 == offset) return HANDLER_GO_ON;
286     const plugin_fn_data *plfd = (const plugin_fn_data *)
287       (((uintptr_t)plugin_slots) + offset);
288     handler_t rc = HANDLER_GO_ON;
289     while (plfd->fn && (rc = plfd->fn(r, plfd->data)) == HANDLER_GO_ON)
290         ++plfd;
291     return rc;
292 }
293 
294 __attribute_hot__
295 static handler_t plugins_call_fn_con_data(connection * const con, const int e) {
296     const void * const plugin_slots = con->plugin_slots;
297     const uint32_t offset = ((const uint16_t *)plugin_slots)[e];
298     if (0 == offset) return HANDLER_GO_ON;
299     const plugin_fn_data *plfd = (const plugin_fn_data *)
300       (((uintptr_t)plugin_slots) + offset);
301     handler_t rc = HANDLER_GO_ON;
302     while (plfd->fn && (rc = plfd->fn(con, plfd->data)) == HANDLER_GO_ON)
303         ++plfd;
304     return rc;
305 }
306 
307 static handler_t plugins_call_fn_srv_data(server * const srv, const int e) {
308     const uint32_t offset = ((const uint16_t *)srv->plugin_slots)[e];
309     if (0 == offset) return HANDLER_GO_ON;
310     const plugin_fn_data *plfd = (const plugin_fn_data *)
311       (((uintptr_t)srv->plugin_slots) + offset);
312     handler_t rc = HANDLER_GO_ON;
313     while (plfd->fn && (rc = plfd->fn(srv,plfd->data)) == HANDLER_GO_ON)
314         ++plfd;
315     return rc;
316 }
317 
318 static void plugins_call_fn_srv_data_all(server * const srv, const int e) {
319     const uint32_t offset = ((const uint16_t *)srv->plugin_slots)[e];
320     if (0 == offset) return;
321     const plugin_fn_data *plfd = (const plugin_fn_data *)
322       (((uintptr_t)srv->plugin_slots) + offset);
323     for (; plfd->fn; ++plfd)
324         plfd->fn(srv, plfd->data);
325 }
326 
327 /**
328  * plugins that use
329  *
330  * - request_st *r
331  * - void *p_d (plugin_data *)
332  */
333 
334 #define PLUGIN_CALL_FN_REQ_DATA(x, y) \
335     handler_t plugins_call_##y(request_st * const r) {\
336         return plugins_call_fn_req_data(r, x); \
337     }
338 
339 PLUGIN_CALL_FN_REQ_DATA(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean)
340 PLUGIN_CALL_FN_REQ_DATA(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot)
341 PLUGIN_CALL_FN_REQ_DATA(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical)
342 PLUGIN_CALL_FN_REQ_DATA(PLUGIN_FUNC_HANDLE_SUBREQUEST_START, handle_subrequest_start)
343 PLUGIN_CALL_FN_REQ_DATA(PLUGIN_FUNC_HANDLE_RESPONSE_START, handle_response_start)
344 PLUGIN_CALL_FN_REQ_DATA(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done)
345 PLUGIN_CALL_FN_REQ_DATA(PLUGIN_FUNC_HANDLE_REQUEST_RESET, handle_request_reset)
346 PLUGIN_CALL_FN_REQ_DATA(PLUGIN_FUNC_HANDLE_REQUEST_ENV, handle_request_env)
347 
348 /**
349  * plugins that use
350  *
351  * - connection *con
352  * - void *p_d (plugin_data *)
353  */
354 
355 #define PLUGIN_CALL_FN_CON_DATA(x, y) \
356     handler_t plugins_call_##y(connection *con) {\
357         return plugins_call_fn_con_data(con, x); \
358     }
359 
360 PLUGIN_CALL_FN_CON_DATA(PLUGIN_FUNC_HANDLE_CONNECTION_ACCEPT, handle_connection_accept)
361 PLUGIN_CALL_FN_CON_DATA(PLUGIN_FUNC_HANDLE_CONNECTION_SHUT_WR, handle_connection_shut_wr)
362 PLUGIN_CALL_FN_CON_DATA(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close)
363 
364 #undef PLUGIN_CALL_FN_SRV_CON_DATA
365 
366 /**
367  * plugins that use
368  *
369  * - server *srv
370  * - void *p_d (plugin_data *)
371  */
372 
373 handler_t plugins_call_set_defaults(server *srv) {
374     return plugins_call_fn_srv_data(srv, PLUGIN_FUNC_SET_DEFAULTS);
375 }
376 
377 handler_t plugins_call_worker_init(server *srv) {
378     return plugins_call_fn_srv_data(srv, PLUGIN_FUNC_WORKER_INIT);
379 }
380 
381 void plugins_call_handle_trigger(server *srv) {
382     plugins_call_fn_srv_data_all(srv, PLUGIN_FUNC_HANDLE_TRIGGER);
383 }
384 
385 void plugins_call_handle_sighup(server *srv) {
386     plugins_call_fn_srv_data_all(srv, PLUGIN_FUNC_HANDLE_SIGHUP);
387 }
388 
389 handler_t plugins_call_handle_waitpid(server *srv, pid_t pid, int status) {
390     const uint32_t offset =
391       ((const uint16_t *)srv->plugin_slots)[PLUGIN_FUNC_HANDLE_WAITPID];
392     if (0 == offset) return HANDLER_GO_ON;
393     const plugin_fn_data *plfd = (const plugin_fn_data *)
394       (((uintptr_t)srv->plugin_slots) + offset);
395     handler_t rc = HANDLER_GO_ON;
396     while (plfd->fn&&(rc=plfd->fn(srv,plfd->data,pid,status))==HANDLER_GO_ON)
397         ++plfd;
398     return rc;
399 }
400 
401 static void plugins_call_cleanup(server * const srv) {
402     plugin ** const ps = srv->plugins.ptr;
403     for (uint32_t i = 0; i < srv->plugins.used; ++i) {
404         plugin *p = ps[i];
405         if (NULL == p) continue;
406         if (NULL != p->data) {
407             plugin_data_base *pd = p->data;
408             if (p->cleanup)
409                 p->cleanup(p->data);
410             free(pd->cvlist);
411             free(pd);
412             p->data = NULL;
413         }
414     }
415 }
416 
417 /**
418  *
419  * - call init function of all plugins to init the plugin-internals
420  * - added each plugin that supports has callback to the corresponding slot
421  *
422  * - is only called once.
423  */
424 
425 __attribute_cold__
426 static void plugins_call_init_slot(server *srv, handler_t(*fn)(), void *data, const uint32_t offset) {
427     if (fn) {
428         plugin_fn_data *plfd = (plugin_fn_data *)
429           (((uintptr_t)srv->plugin_slots) + offset);
430         while (plfd->fn) ++plfd;
431         plfd->fn = fn;
432         plfd->data = data;
433     }
434 }
435 
436 handler_t plugins_call_init(server *srv) {
437 	plugin ** const ps = srv->plugins.ptr;
438 	uint16_t offsets[PLUGIN_FUNC_SIZEOF];
439 	memset(offsets, 0, sizeof(offsets));
440 
441 	for (uint32_t i = 0; i < srv->plugins.used; ++i) {
442 		/* check which calls are supported */
443 
444 		plugin *p = ps[i];
445 
446 		if (p->init) {
447 			if (NULL == (p->data = p->init())) {
448 				log_error(srv->errh, __FILE__, __LINE__,
449 				  "plugin-init failed for module %s", p->name);
450 				return HANDLER_ERROR;
451 			}
452 
453 			((plugin_data_base *)(p->data))->self = p;
454 			((plugin_data_base *)(p->data))->id = i + 1;
455 
456 			if (p->version != LIGHTTPD_VERSION_ID) {
457 				log_error(srv->errh, __FILE__, __LINE__,
458 				  "plugin-version doesn't match lighttpd-version for %s", p->name);
459 				return HANDLER_ERROR;
460 			}
461 		}
462 
463 		if (p->priv_defaults && HANDLER_ERROR==p->priv_defaults(srv, p->data)) {
464 			return HANDLER_ERROR;
465 		}
466 
467 		if (p->handle_uri_clean)
468 			++offsets[PLUGIN_FUNC_HANDLE_URI_CLEAN];
469 		if (p->handle_uri_raw && !p->handle_uri_clean)
470 			++offsets[PLUGIN_FUNC_HANDLE_URI_CLEAN]; /*(same as above)*/
471 		if (p->handle_request_env)
472 			++offsets[PLUGIN_FUNC_HANDLE_REQUEST_ENV];
473 		if (p->handle_request_done)
474 			++offsets[PLUGIN_FUNC_HANDLE_REQUEST_DONE];
475 		if (p->handle_connection_accept)
476 			++offsets[PLUGIN_FUNC_HANDLE_CONNECTION_ACCEPT];
477 		if (p->handle_connection_shut_wr)
478 			++offsets[PLUGIN_FUNC_HANDLE_CONNECTION_SHUT_WR];
479 		if (p->handle_connection_close)
480 			++offsets[PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE];
481 		if (p->handle_trigger)
482 			++offsets[PLUGIN_FUNC_HANDLE_TRIGGER];
483 		if (p->handle_sighup)
484 			++offsets[PLUGIN_FUNC_HANDLE_SIGHUP];
485 		if (p->handle_waitpid)
486 			++offsets[PLUGIN_FUNC_HANDLE_WAITPID];
487 		if (p->handle_subrequest_start)
488 			++offsets[PLUGIN_FUNC_HANDLE_SUBREQUEST_START];
489 		if (p->handle_response_start)
490 			++offsets[PLUGIN_FUNC_HANDLE_RESPONSE_START];
491 		if (p->handle_docroot)
492 			++offsets[PLUGIN_FUNC_HANDLE_DOCROOT];
493 		if (p->handle_physical)
494 			++offsets[PLUGIN_FUNC_HANDLE_PHYSICAL];
495 		if (p->handle_request_reset)
496 			++offsets[PLUGIN_FUNC_HANDLE_REQUEST_RESET];
497 		if (p->set_defaults)
498 			++offsets[PLUGIN_FUNC_SET_DEFAULTS];
499 		if (p->worker_init)
500 			++offsets[PLUGIN_FUNC_WORKER_INIT];
501 	}
502 
503 	uint32_t nslots =
504 	  (sizeof(offsets)+sizeof(plugin_fn_data)-1) / sizeof(plugin_fn_data);
505 	for (uint32_t i = 0; i < PLUGIN_FUNC_SIZEOF; ++i) {
506 		if (offsets[i]) {
507 			uint32_t offset = nslots;
508 			nslots += offsets[i]+1; /* +1 to mark end of each list */
509 			force_assert(offset * sizeof(plugin_fn_data) <= USHRT_MAX);
510 			offsets[i] = (uint16_t)(offset * sizeof(plugin_fn_data));
511 		}
512 	}
513 
514 	/* allocate and fill slots of two dimensional array */
515 	srv->plugin_slots = calloc(nslots, sizeof(plugin_fn_data));
516 	force_assert(NULL != srv->plugin_slots);
517 	memcpy(srv->plugin_slots, offsets, sizeof(offsets));
518 
519 	/* add handle_uri_raw before handle_uri_clean, but in same slot */
520 	for (uint32_t i = 0; i < srv->plugins.used; ++i) {
521 		plugin * const p = ps[i];
522 		plugins_call_init_slot(srv, p->handle_uri_raw, p->data,
523 					offsets[PLUGIN_FUNC_HANDLE_URI_CLEAN]);
524 	}
525 
526 	for (uint32_t i = 0; i < srv->plugins.used; ++i) {
527 		plugin * const p = ps[i];
528 
529 		if (!p->handle_uri_raw)
530 			plugins_call_init_slot(srv, p->handle_uri_clean, p->data,
531 						offsets[PLUGIN_FUNC_HANDLE_URI_CLEAN]);
532 		plugins_call_init_slot(srv, p->handle_request_env, p->data,
533 					offsets[PLUGIN_FUNC_HANDLE_REQUEST_ENV]);
534 		plugins_call_init_slot(srv, p->handle_request_done, p->data,
535 					offsets[PLUGIN_FUNC_HANDLE_REQUEST_DONE]);
536 		plugins_call_init_slot(srv, p->handle_connection_accept, p->data,
537 					offsets[PLUGIN_FUNC_HANDLE_CONNECTION_ACCEPT]);
538 		plugins_call_init_slot(srv, p->handle_connection_shut_wr, p->data,
539 					offsets[PLUGIN_FUNC_HANDLE_CONNECTION_SHUT_WR]);
540 		plugins_call_init_slot(srv, p->handle_connection_close, p->data,
541 					offsets[PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE]);
542 		plugins_call_init_slot(srv, p->handle_trigger, p->data,
543 					offsets[PLUGIN_FUNC_HANDLE_TRIGGER]);
544 		plugins_call_init_slot(srv, p->handle_sighup, p->data,
545 					offsets[PLUGIN_FUNC_HANDLE_SIGHUP]);
546 		plugins_call_init_slot(srv, p->handle_waitpid, p->data,
547 					offsets[PLUGIN_FUNC_HANDLE_WAITPID]);
548 		plugins_call_init_slot(srv, p->handle_subrequest_start, p->data,
549 					offsets[PLUGIN_FUNC_HANDLE_SUBREQUEST_START]);
550 		plugins_call_init_slot(srv, p->handle_response_start, p->data,
551 					offsets[PLUGIN_FUNC_HANDLE_RESPONSE_START]);
552 		plugins_call_init_slot(srv, p->handle_docroot, p->data,
553 					offsets[PLUGIN_FUNC_HANDLE_DOCROOT]);
554 		plugins_call_init_slot(srv, p->handle_physical, p->data,
555 					offsets[PLUGIN_FUNC_HANDLE_PHYSICAL]);
556 		plugins_call_init_slot(srv, p->handle_request_reset, p->data,
557 					offsets[PLUGIN_FUNC_HANDLE_REQUEST_RESET]);
558 		plugins_call_init_slot(srv, p->set_defaults, p->data,
559 					offsets[PLUGIN_FUNC_SET_DEFAULTS]);
560 		plugins_call_init_slot(srv, p->worker_init, p->data,
561 					offsets[PLUGIN_FUNC_WORKER_INIT]);
562 	}
563 
564 	return HANDLER_GO_ON;
565 }
566 
567 void plugins_free(server *srv) {
568 	if (srv->plugin_slots) {
569 		plugins_call_cleanup(srv);
570 		free(srv->plugin_slots);
571 		srv->plugin_slots = NULL;
572 	}
573 
574 	for (uint32_t i = 0; i < srv->plugins.used; ++i) {
575 		plugin_free(((plugin **)srv->plugins.ptr)[i]);
576 	}
577 	free(srv->plugins.ptr);
578 	srv->plugins.ptr = NULL;
579 	srv->plugins.used = 0;
580 	srv->plugins.size = 0;
581 	array_free_data(&plugin_stats);
582 }
583