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