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; 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 buffer_copy_string_buffer(srv->tmp_buf, srv->srvconf.modules_dir); 130 131 buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("/")); 132 buffer_append_string(srv->tmp_buf, modules); 133 #if defined(__WIN32) || defined(__CYGWIN__) 134 buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN(".dll")); 135 #else 136 buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN(".so")); 137 #endif 138 139 p = plugin_init(); 140 #ifdef __WIN32 141 if (NULL == (p->lib = LoadLibrary(srv->tmp_buf->ptr))) { 142 LPVOID lpMsgBuf; 143 FormatMessage( 144 FORMAT_MESSAGE_ALLOCATE_BUFFER | 145 FORMAT_MESSAGE_FROM_SYSTEM, 146 NULL, 147 GetLastError(), 148 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 149 (LPTSTR) &lpMsgBuf, 150 0, NULL ); 151 152 log_error_write(srv, __FILE__, __LINE__, "ssb", "LoadLibrary() failed", 153 lpMsgBuf, srv->tmp_buf); 154 155 plugin_free(p); 156 157 return -1; 158 159 } 160 #else 161 if (NULL == (p->lib = dlopen(srv->tmp_buf->ptr, RTLD_NOW|RTLD_GLOBAL))) { 162 log_error_write(srv, __FILE__, __LINE__, "sbs", "dlopen() failed for:", 163 srv->tmp_buf, dlerror()); 164 165 plugin_free(p); 166 167 return -1; 168 } 169 170 #endif 171 buffer_reset(srv->tmp_buf); 172 buffer_copy_string(srv->tmp_buf, modules); 173 buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("_plugin_init")); 174 175 #ifdef __WIN32 176 init = GetProcAddress(p->lib, srv->tmp_buf->ptr); 177 178 if (init == NULL) { 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_write(srv, __FILE__, __LINE__, "sbs", "getprocaddress failed:", srv->tmp_buf, lpMsgBuf); 190 191 plugin_free(p); 192 return -1; 193 } 194 195 #else 196 #if 1 197 init = (int (*)(plugin *))(intptr_t)dlsym(p->lib, srv->tmp_buf->ptr); 198 #else 199 *(void **)(&init) = dlsym(p->lib, srv->tmp_buf->ptr); 200 #endif 201 if ((error = dlerror()) != NULL) { 202 log_error_write(srv, __FILE__, __LINE__, "s", error); 203 204 plugin_free(p); 205 return -1; 206 } 207 208 #endif 209 if ((*init)(p)) { 210 log_error_write(srv, __FILE__, __LINE__, "ss", modules, "plugin init failed" ); 211 212 plugin_free(p); 213 return -1; 214 } 215 #if 0 216 log_error_write(srv, __FILE__, __LINE__, "ss", modules, "plugin loaded" ); 217 #endif 218 plugins_register(srv, p); 219 } 220 221 return 0; 222 } 223 #endif 224 225 #define PLUGIN_TO_SLOT(x, y) \ 226 handler_t plugins_call_##y(server *srv, connection *con) {\ 227 plugin **slot;\ 228 size_t j;\ 229 if (!srv->plugin_slots) return HANDLER_GO_ON;\ 230 slot = ((plugin ***)(srv->plugin_slots))[x];\ 231 if (!slot) return HANDLER_GO_ON;\ 232 for (j = 0; j < srv->plugins.used && slot[j]; j++) { \ 233 plugin *p = slot[j];\ 234 handler_t r;\ 235 switch(r = p->y(srv, con, p->data)) {\ 236 case HANDLER_GO_ON:\ 237 break;\ 238 case HANDLER_FINISHED:\ 239 case HANDLER_COMEBACK:\ 240 case HANDLER_WAIT_FOR_EVENT:\ 241 case HANDLER_WAIT_FOR_FD:\ 242 case HANDLER_ERROR:\ 243 return r;\ 244 default:\ 245 log_error_write(srv, __FILE__, __LINE__, "sbs", #x, p->name, "unknown state");\ 246 return HANDLER_ERROR;\ 247 }\ 248 }\ 249 return HANDLER_GO_ON;\ 250 } 251 252 /** 253 * plugins that use 254 * 255 * - server *srv 256 * - connection *con 257 * - void *p_d (plugin_data *) 258 */ 259 260 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean) 261 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw) 262 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done) 263 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close) 264 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST, handle_subrequest) 265 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST_START, handle_subrequest_start) 266 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_JOBLIST, handle_joblist) 267 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot) 268 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical) 269 PLUGIN_TO_SLOT(PLUGIN_FUNC_CONNECTION_RESET, connection_reset) 270 271 #undef PLUGIN_TO_SLOT 272 273 #define PLUGIN_TO_SLOT(x, y) \ 274 handler_t plugins_call_##y(server *srv) {\ 275 plugin **slot;\ 276 size_t j;\ 277 if (!srv->plugin_slots) return HANDLER_GO_ON;\ 278 slot = ((plugin ***)(srv->plugin_slots))[x];\ 279 if (!slot) return HANDLER_GO_ON;\ 280 for (j = 0; j < srv->plugins.used && slot[j]; j++) { \ 281 plugin *p = slot[j];\ 282 handler_t r;\ 283 switch(r = p->y(srv, p->data)) {\ 284 case HANDLER_GO_ON:\ 285 break;\ 286 case HANDLER_FINISHED:\ 287 case HANDLER_COMEBACK:\ 288 case HANDLER_WAIT_FOR_EVENT:\ 289 case HANDLER_WAIT_FOR_FD:\ 290 case HANDLER_ERROR:\ 291 return r;\ 292 default:\ 293 log_error_write(srv, __FILE__, __LINE__, "sbsd", #x, p->name, "unknown state:", r);\ 294 return HANDLER_ERROR;\ 295 }\ 296 }\ 297 return HANDLER_GO_ON;\ 298 } 299 300 /** 301 * plugins that use 302 * 303 * - server *srv 304 * - void *p_d (plugin_data *) 305 */ 306 307 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger) 308 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup) 309 PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup) 310 PLUGIN_TO_SLOT(PLUGIN_FUNC_SET_DEFAULTS, set_defaults) 311 312 #undef PLUGIN_TO_SLOT 313 314 #if 0 315 /** 316 * 317 * special handler 318 * 319 */ 320 handler_t plugins_call_handle_fdevent(server *srv, const fd_conn *fdc) { 321 size_t i; 322 plugin **ps; 323 324 ps = srv->plugins.ptr; 325 326 for (i = 0; i < srv->plugins.used; i++) { 327 plugin *p = ps[i]; 328 if (p->handle_fdevent) { 329 handler_t r; 330 switch(r = p->handle_fdevent(srv, fdc, p->data)) { 331 case HANDLER_GO_ON: 332 break; 333 case HANDLER_FINISHED: 334 case HANDLER_COMEBACK: 335 case HANDLER_WAIT_FOR_EVENT: 336 case HANDLER_ERROR: 337 return r; 338 default: 339 log_error_write(srv, __FILE__, __LINE__, "d", r); 340 break; 341 } 342 } 343 } 344 345 return HANDLER_GO_ON; 346 } 347 #endif 348 /** 349 * 350 * - call init function of all plugins to init the plugin-internals 351 * - added each plugin that supports has callback to the corresponding slot 352 * 353 * - is only called once. 354 */ 355 356 handler_t plugins_call_init(server *srv) { 357 size_t i; 358 plugin **ps; 359 360 ps = srv->plugins.ptr; 361 362 /* fill slots */ 363 364 srv->plugin_slots = calloc(PLUGIN_FUNC_SIZEOF, sizeof(ps)); 365 366 for (i = 0; i < srv->plugins.used; i++) { 367 size_t j; 368 /* check which calls are supported */ 369 370 plugin *p = ps[i]; 371 372 #define PLUGIN_TO_SLOT(x, y) \ 373 if (p->y) { \ 374 plugin **slot = ((plugin ***)(srv->plugin_slots))[x]; \ 375 if (!slot) { \ 376 slot = calloc(srv->plugins.used, sizeof(*slot));\ 377 ((plugin ***)(srv->plugin_slots))[x] = slot; \ 378 } \ 379 for (j = 0; j < srv->plugins.used; j++) { \ 380 if (slot[j]) continue;\ 381 slot[j] = p;\ 382 break;\ 383 }\ 384 } 385 386 387 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean); 388 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw); 389 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done); 390 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close); 391 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger); 392 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup); 393 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST, handle_subrequest); 394 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST_START, handle_subrequest_start); 395 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_JOBLIST, handle_joblist); 396 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot); 397 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical); 398 PLUGIN_TO_SLOT(PLUGIN_FUNC_CONNECTION_RESET, connection_reset); 399 PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup); 400 PLUGIN_TO_SLOT(PLUGIN_FUNC_SET_DEFAULTS, set_defaults); 401 #undef PLUGIN_TO_SLOT 402 403 if (p->init) { 404 if (NULL == (p->data = p->init())) { 405 log_error_write(srv, __FILE__, __LINE__, "sb", 406 "plugin-init failed for module", p->name); 407 return HANDLER_ERROR; 408 } 409 410 /* used for con->mode, DIRECT == 0, plugins above that */ 411 ((plugin_data *)(p->data))->id = i + 1; 412 413 if (p->version != LIGHTTPD_VERSION_ID) { 414 log_error_write(srv, __FILE__, __LINE__, "sb", 415 "plugin-version doesn't match lighttpd-version for", p->name); 416 return HANDLER_ERROR; 417 } 418 } else { 419 p->data = NULL; 420 } 421 } 422 423 return HANDLER_GO_ON; 424 } 425 426 void plugins_free(server *srv) { 427 size_t i; 428 plugins_call_cleanup(srv); 429 430 for (i = 0; i < srv->plugins.used; i++) { 431 plugin *p = ((plugin **)srv->plugins.ptr)[i]; 432 433 plugin_free(p); 434 } 435 436 for (i = 0; srv->plugin_slots && i < PLUGIN_FUNC_SIZEOF; i++) { 437 plugin **slot = ((plugin ***)(srv->plugin_slots))[i]; 438 439 if (slot) free(slot); 440 } 441 442 free(srv->plugin_slots); 443 srv->plugin_slots = NULL; 444 445 free(srv->plugins.ptr); 446 srv->plugins.ptr = NULL; 447 srv->plugins.used = 0; 448 } 449