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