/src/fluent-bit/lib/monkey/mk_server/mk_plugin.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | |
3 | | /* Monkey HTTP Server |
4 | | * ================== |
5 | | * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io> |
6 | | * |
7 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
8 | | * you may not use this file except in compliance with the License. |
9 | | * You may obtain a copy of the License at |
10 | | * |
11 | | * http://www.apache.org/licenses/LICENSE-2.0 |
12 | | * |
13 | | * Unless required by applicable law or agreed to in writing, software |
14 | | * distributed under the License is distributed on an "AS IS" BASIS, |
15 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | | * See the License for the specific language governing permissions and |
17 | | * limitations under the License. |
18 | | */ |
19 | | |
20 | | #include <monkey/monkey.h> |
21 | | #include <monkey/mk_utils.h> |
22 | | #include <monkey/mk_http.h> |
23 | | #include <monkey/mk_clock.h> |
24 | | #include <monkey/mk_plugin.h> |
25 | | #include <monkey/mk_mimetype.h> |
26 | | #include <monkey/mk_vhost.h> |
27 | | #include <monkey/mk_static_plugins.h> |
28 | | #include <monkey/mk_plugin_stage.h> |
29 | | #include <monkey/mk_core.h> |
30 | | #include <monkey/mk_net.h> |
31 | | |
32 | | #ifndef _WIN32 |
33 | | #include <dlfcn.h> |
34 | | #include <err.h> |
35 | | #endif |
36 | | |
37 | | enum { |
38 | | bufsize = 256 |
39 | | }; |
40 | | |
41 | | static struct plugin_stagemap *plg_stagemap; |
42 | | struct plugin_network_io *plg_netiomap; |
43 | | |
44 | | struct mk_plugin *mk_plugin_lookup(char *shortname, struct mk_server *server) |
45 | 0 | { |
46 | 0 | struct mk_list *head; |
47 | 0 | struct mk_plugin *p = NULL; |
48 | |
|
49 | 0 | mk_list_foreach(head, &server->plugins) { |
50 | 0 | p = mk_list_entry(head, struct mk_plugin, _head); |
51 | 0 | if (strcmp(p->shortname, shortname) == 0){ |
52 | 0 | return p; |
53 | 0 | } |
54 | 0 | } |
55 | | |
56 | 0 | return NULL; |
57 | 0 | } |
58 | | |
59 | | void *mk_plugin_load_dynamic(const char *path) |
60 | 0 | { |
61 | 0 | void *handle; |
62 | |
|
63 | | #ifdef _WIN32 |
64 | | handle = (void *) LoadLibraryA(path); |
65 | | #else |
66 | 0 | handle = dlopen(path, RTLD_LAZY); |
67 | |
|
68 | 0 | if (!handle) { |
69 | 0 | mk_warn("dlopen() %s", dlerror()); |
70 | 0 | } |
71 | 0 | #endif |
72 | |
|
73 | 0 | return handle; |
74 | 0 | } |
75 | | |
76 | | void *mk_plugin_load_symbol(void *handler, const char *symbol) |
77 | 0 | { |
78 | 0 | void *s; |
79 | |
|
80 | | #ifdef _WIN32 |
81 | | s = GetProcAddress((HMODULE)handler, symbol); |
82 | | #else |
83 | 0 | dlerror(); |
84 | 0 | s = dlsym(handler, symbol); |
85 | 0 | if (dlerror() != NULL) { |
86 | 0 | return NULL; |
87 | 0 | } |
88 | 0 | #endif |
89 | | |
90 | 0 | return s; |
91 | 0 | } |
92 | | |
93 | | /* Initialize a plugin, trigger the init_plugin callback */ |
94 | | static int mk_plugin_init(struct plugin_api *api, |
95 | | struct mk_plugin *plugin, |
96 | | struct mk_server *server) |
97 | 0 | { |
98 | 0 | int ret; |
99 | 0 | unsigned long len; |
100 | 0 | char path[1024]; |
101 | 0 | char *conf_dir = NULL; |
102 | 0 | struct file_info f_info; |
103 | |
|
104 | 0 | MK_TRACE("Load Plugin: '%s'", plugin->shortname); |
105 | |
|
106 | 0 | snprintf(path, 1024, "%s/%s", |
107 | 0 | server->path_conf_root, server->conf_plugins); |
108 | 0 | ret = mk_file_get_info(path, &f_info, MK_FILE_READ); |
109 | 0 | if (ret == -1 || f_info.is_directory == MK_FALSE) { |
110 | 0 | snprintf(path, 1024, "%s", server->conf_plugins); |
111 | 0 | } |
112 | | |
113 | | /* Build plugin configuration path */ |
114 | 0 | mk_string_build(&conf_dir, |
115 | 0 | &len, |
116 | 0 | "%s/%s/", |
117 | 0 | path, plugin->shortname); |
118 | | |
119 | | /* Init plugin */ |
120 | 0 | plugin->api = api; |
121 | 0 | plugin->server_ctx = server; |
122 | |
|
123 | 0 | if (plugin->network != NULL) { |
124 | 0 | plugin->network->plugin = plugin; |
125 | 0 | } |
126 | |
|
127 | 0 | ret = plugin->init_plugin(plugin, conf_dir); |
128 | 0 | mk_mem_free(conf_dir); |
129 | |
|
130 | 0 | return ret; |
131 | 0 | } |
132 | | |
133 | | |
134 | | /* |
135 | | * Load a plugin into Monkey core, 'type' defines if it's a MK_PLUGIN_STATIC or |
136 | | * a MK_PLUGIN_DYNAMIC. 'shortname' is mandatory and 'path' is only used when |
137 | | * MK_PLUGIN_DYNAMIC is set and represents the absolute path of the shared |
138 | | * library. |
139 | | */ |
140 | | struct mk_plugin *mk_plugin_load(int type, const char *shortname, |
141 | | void *data, struct mk_server *server) |
142 | 0 | { |
143 | 0 | char *path; |
144 | 0 | char symbol[64]; |
145 | 0 | void *handler; |
146 | 0 | struct mk_list *head; |
147 | 0 | struct mk_plugin *tmp; |
148 | 0 | struct mk_plugin *plugin = NULL; |
149 | 0 | struct mk_plugin_stage *stage; |
150 | | |
151 | | /* Set main struct name to reference */ |
152 | 0 | if (type == MK_PLUGIN_DYNAMIC) { |
153 | 0 | path = (char *) data; |
154 | 0 | handler = mk_plugin_load_dynamic(path); |
155 | 0 | if (!handler) { |
156 | 0 | return NULL; |
157 | 0 | } |
158 | | |
159 | 0 | snprintf(symbol, sizeof(symbol) - 1, "mk_plugin_%s", shortname); |
160 | 0 | plugin = mk_plugin_load_symbol(handler, symbol); |
161 | 0 | if (!plugin) { |
162 | 0 | mk_warn("Plugin '%s' is not registering properly", path); |
163 | | #ifdef _WIN32 |
164 | | FreeLibrary((HMODULE)handler); |
165 | | #else |
166 | 0 | dlclose(handler); |
167 | 0 | #endif |
168 | 0 | return NULL; |
169 | 0 | } |
170 | | |
171 | | /* Make sure this is not loaded twice (ref #218) */ |
172 | 0 | mk_list_foreach(head, &server->plugins) { |
173 | 0 | tmp = mk_list_entry(head, struct mk_plugin, _head); |
174 | 0 | if (tmp->load_type == MK_PLUGIN_STATIC && |
175 | 0 | strcmp(tmp->name, plugin->name) == 0){ |
176 | 0 | mk_warn("Plugin '%s' have been built-in.", |
177 | 0 | tmp->shortname); |
178 | | #ifdef _WIN32 |
179 | | FreeLibrary((HMODULE)handler); |
180 | | #else |
181 | 0 | dlclose(handler); |
182 | 0 | #endif |
183 | 0 | return NULL; |
184 | 0 | } |
185 | 0 | } |
186 | | |
187 | 0 | plugin->load_type = MK_PLUGIN_DYNAMIC; |
188 | 0 | plugin->handler = handler; |
189 | 0 | plugin->path = mk_string_dup(path); |
190 | 0 | } |
191 | 0 | else if (type == MK_PLUGIN_STATIC) { |
192 | 0 | plugin = (struct mk_plugin *) data; |
193 | 0 | plugin->load_type = MK_PLUGIN_STATIC; |
194 | 0 | } |
195 | | |
196 | 0 | if (!plugin) { |
197 | 0 | return NULL; |
198 | 0 | } |
199 | | |
200 | | /* Validate all callbacks are set */ |
201 | 0 | if (!plugin->shortname || !plugin->name || !plugin->version || |
202 | 0 | !plugin->init_plugin || !plugin->exit_plugin) { |
203 | 0 | mk_warn("Plugin '%s' is not registering all fields properly", |
204 | 0 | shortname); |
205 | 0 | return NULL; |
206 | 0 | } |
207 | | |
208 | 0 | if (plugin->hooks & MK_PLUGIN_NETWORK_LAYER) { |
209 | 0 | mk_bug(!plugin->network); |
210 | 0 | } |
211 | | |
212 | 0 | mk_list_init(&plugin->stage_list); |
213 | 0 | if (plugin->hooks & MK_PLUGIN_STAGE) { |
214 | 0 | struct mk_plugin_stage *st; |
215 | |
|
216 | 0 | stage = plugin->stage; |
217 | 0 | if (stage->stage10) { |
218 | 0 | st = mk_mem_alloc(sizeof(struct mk_plugin_stage)); |
219 | 0 | st->stage10 = stage->stage10; |
220 | 0 | st->plugin = plugin; |
221 | 0 | mk_list_add(&st->_head, &server->stage10_handler); |
222 | 0 | mk_list_add(&st->_parent_head, &plugin->stage_list); |
223 | 0 | } |
224 | 0 | if (stage->stage20) { |
225 | 0 | st = mk_mem_alloc(sizeof(struct mk_plugin_stage)); |
226 | 0 | st->stage20 = stage->stage20; |
227 | 0 | st->plugin = plugin; |
228 | 0 | mk_list_add(&st->_head, &server->stage20_handler); |
229 | 0 | mk_list_add(&st->_parent_head, &plugin->stage_list); |
230 | 0 | } |
231 | 0 | if (stage->stage30) { |
232 | 0 | st = mk_mem_alloc(sizeof(struct mk_plugin_stage)); |
233 | 0 | st->stage30 = stage->stage30; |
234 | 0 | st->plugin = plugin; |
235 | 0 | mk_list_add(&st->_head, &server->stage30_handler); |
236 | 0 | mk_list_add(&st->_parent_head, &plugin->stage_list); |
237 | 0 | } |
238 | 0 | if (stage->stage40) { |
239 | 0 | st = mk_mem_alloc(sizeof(struct mk_plugin_stage)); |
240 | 0 | st->stage40 = stage->stage40; |
241 | 0 | st->plugin = plugin; |
242 | 0 | mk_list_add(&st->_head, &server->stage40_handler); |
243 | 0 | mk_list_add(&st->_parent_head, &plugin->stage_list); |
244 | 0 | } |
245 | 0 | if (stage->stage50) { |
246 | 0 | st = mk_mem_alloc(sizeof(struct mk_plugin_stage)); |
247 | 0 | st->stage50 = stage->stage50; |
248 | 0 | st->plugin = plugin; |
249 | 0 | mk_list_add(&st->_head, &server->stage50_handler); |
250 | 0 | mk_list_add(&st->_parent_head, &plugin->stage_list); |
251 | 0 | } |
252 | 0 | } |
253 | |
|
254 | 0 | if (type == MK_PLUGIN_DYNAMIC) { |
255 | | /* Add Plugin to the end of the list */ |
256 | 0 | mk_list_add(&plugin->_head, &server->plugins); |
257 | 0 | } |
258 | |
|
259 | 0 | return plugin; |
260 | 0 | } |
261 | | |
262 | | void mk_plugin_unregister(struct mk_plugin *p) |
263 | 0 | { |
264 | 0 | mk_mem_free(p->path); |
265 | 0 | mk_list_del(&p->_head); |
266 | 0 | if (p->load_type == MK_PLUGIN_DYNAMIC) { |
267 | | #ifdef _WIN32 |
268 | | FreeLibrary((HMODULE)p->handler); |
269 | | #else |
270 | 0 | dlclose(p->handler); |
271 | 0 | #endif |
272 | 0 | } |
273 | |
|
274 | 0 | } |
275 | | |
276 | | void mk_plugin_api_init(struct mk_server *server) |
277 | 0 | { |
278 | 0 | struct plugin_api *api; |
279 | | |
280 | | /* Create an instance of the API */ |
281 | 0 | api = mk_mem_alloc_z(sizeof(struct plugin_api)); |
282 | |
|
283 | 0 | #ifndef _WIN32 |
284 | 0 | __builtin_prefetch(api); |
285 | 0 | #endif |
286 | | |
287 | | /* Setup and connections list */ |
288 | | /* FIXME: api->config = server; */ |
289 | | |
290 | | /* API plugins funcions */ |
291 | | |
292 | | /* Error helper */ |
293 | 0 | api->_error = mk_print; |
294 | | |
295 | | /* HTTP callbacks */ |
296 | 0 | api->http_request_end = mk_plugin_http_request_end; |
297 | 0 | api->http_request_error = mk_plugin_http_error; |
298 | | |
299 | | /* Memory callbacks */ |
300 | 0 | api->pointer_set = mk_ptr_set; |
301 | 0 | api->pointer_print = mk_ptr_print; |
302 | 0 | api->pointer_to_buf = mk_ptr_to_buf; |
303 | 0 | api->plugin_load_symbol = mk_plugin_load_symbol; |
304 | 0 | api->mem_alloc = mk_mem_alloc; |
305 | 0 | api->mem_alloc_z = mk_mem_alloc_z; |
306 | 0 | api->mem_realloc = mk_mem_realloc; |
307 | 0 | api->mem_free = mk_mem_free; |
308 | | |
309 | | /* String Callbacks */ |
310 | 0 | api->str_build = mk_string_build; |
311 | 0 | api->str_dup = mk_string_dup; |
312 | 0 | api->str_search = mk_string_search; |
313 | 0 | api->str_search_n = mk_string_search_n; |
314 | 0 | api->str_char_search = mk_string_char_search; |
315 | 0 | api->str_copy_substr = mk_string_copy_substr; |
316 | 0 | api->str_itop = mk_string_itop; |
317 | 0 | api->str_split_line = mk_string_split_line; |
318 | 0 | api->str_split_free = mk_string_split_free; |
319 | | |
320 | | /* File Callbacks */ |
321 | 0 | api->file_to_buffer = mk_file_to_buffer; |
322 | 0 | api->file_get_info = mk_file_get_info; |
323 | | |
324 | | /* HTTP Callbacks */ |
325 | 0 | api->header_prepare = mk_plugin_header_prepare; |
326 | 0 | api->header_add = mk_plugin_header_add; |
327 | 0 | api->header_get = mk_http_header_get; |
328 | 0 | api->header_set_http_status = mk_header_set_http_status; |
329 | | |
330 | | /* Channels / Streams */ |
331 | 0 | api->channel_new = mk_channel_new; |
332 | 0 | api->channel_flush = mk_channel_flush; |
333 | 0 | api->channel_write = mk_channel_write; |
334 | 0 | api->channel_append_stream = mk_channel_append_stream; |
335 | | |
336 | | /* IOV callbacks */ |
337 | 0 | api->iov_create = mk_iov_create; |
338 | 0 | api->iov_realloc = mk_iov_realloc; |
339 | 0 | api->iov_free = mk_iov_free; |
340 | 0 | api->iov_free_marked = mk_iov_free_marked; |
341 | 0 | api->iov_add = mk_iov_add; |
342 | 0 | api->iov_set_entry = mk_iov_set_entry; |
343 | 0 | api->iov_send = mk_iov_send; |
344 | 0 | api->iov_print = mk_iov_print; |
345 | | |
346 | | /* events mechanism */ |
347 | 0 | api->ev_loop_create = mk_event_loop_create; |
348 | 0 | api->ev_add = mk_event_add; |
349 | 0 | api->ev_del = mk_event_del; |
350 | 0 | api->ev_timeout_create = mk_event_timeout_create; |
351 | 0 | api->ev_channel_create = mk_event_channel_create; |
352 | 0 | api->ev_wait = mk_event_wait; |
353 | 0 | api->ev_backend = mk_event_backend; |
354 | | |
355 | | /* Mimetype */ |
356 | 0 | api->mimetype_lookup = mk_mimetype_lookup; |
357 | | |
358 | | /* Socket callbacks */ |
359 | 0 | api->socket_cork_flag = mk_socket_set_cork_flag; |
360 | 0 | api->socket_connect = mk_socket_connect; |
361 | 0 | api->socket_open = mk_socket_open; |
362 | 0 | api->socket_reset = mk_socket_reset; |
363 | 0 | api->socket_set_tcp_fastopen = mk_socket_set_tcp_fastopen; |
364 | 0 | api->socket_set_tcp_reuseport = mk_socket_set_tcp_reuseport; |
365 | 0 | api->socket_set_tcp_nodelay = mk_socket_set_tcp_nodelay; |
366 | 0 | api->socket_set_nonblocking = mk_socket_set_nonblocking; |
367 | 0 | api->socket_create = mk_socket_create; |
368 | 0 | api->socket_ip_str = mk_socket_ip_str; |
369 | | |
370 | | /* Async network */ |
371 | 0 | api->net_conn_create = mk_net_conn_create; |
372 | | |
373 | | /* Config Callbacks */ |
374 | 0 | api->config_create = mk_rconf_create; |
375 | 0 | api->config_open = mk_rconf_open; |
376 | 0 | api->config_free = mk_rconf_free; |
377 | 0 | api->config_section_get = mk_rconf_section_get; |
378 | 0 | api->config_section_get_key = mk_rconf_section_get_key; |
379 | | |
380 | | /* Scheduler and Event callbacks */ |
381 | 0 | api->sched_loop = mk_sched_loop; |
382 | 0 | api->sched_get_connection = mk_sched_get_connection; |
383 | 0 | api->sched_event_free = mk_sched_event_free; |
384 | 0 | api->sched_remove_client = mk_plugin_sched_remove_client; |
385 | 0 | api->sched_worker_info = mk_plugin_sched_get_thread_conf; |
386 | | |
387 | | /* Worker functions */ |
388 | 0 | api->worker_spawn = mk_utils_worker_spawn; |
389 | 0 | api->worker_rename = mk_utils_worker_rename; |
390 | | |
391 | | /* Time functions */ |
392 | 0 | api->time_unix = mk_plugin_time_now_unix; |
393 | 0 | api->time_to_gmt = mk_utils_utime2gmt; |
394 | 0 | api->time_human = mk_plugin_time_now_human; |
395 | |
|
396 | 0 | api->stacktrace = (void *) mk_utils_stacktrace; |
397 | 0 | api->kernel_version = mk_kernel_version; |
398 | 0 | api->kernel_features_print = mk_kernel_features_print; |
399 | 0 | api->plugins = &server->plugins; |
400 | | |
401 | | /* handler */ |
402 | 0 | api->handler_param_get = mk_handler_param_get; |
403 | |
|
404 | 0 | server->api = api; |
405 | 0 | } |
406 | | |
407 | | void mk_plugin_load_static(struct mk_server *server) |
408 | 0 | { |
409 | | /* Load static plugins */ |
410 | 0 | mk_list_init(&server->plugins); |
411 | 0 | mk_static_plugins(&server->plugins); |
412 | 0 | } |
413 | | |
414 | | void mk_plugin_load_all(struct mk_server *server) |
415 | 0 | { |
416 | 0 | int ret; |
417 | 0 | char *tmp; |
418 | 0 | char *path; |
419 | 0 | char shortname[64]; |
420 | 0 | struct mk_plugin *p; |
421 | 0 | struct mk_rconf *cnf; |
422 | 0 | struct mk_rconf_section *section; |
423 | 0 | struct mk_rconf_entry *entry; |
424 | 0 | struct mk_list *head; |
425 | 0 | struct mk_list *htmp; |
426 | 0 | struct file_info f_info; |
427 | |
|
428 | 0 | mk_plugin_load_static(server); |
429 | 0 | mk_list_foreach_safe(head, htmp, &server->plugins) { |
430 | 0 | p = mk_list_entry(head, struct mk_plugin, _head); |
431 | | |
432 | | /* Load the static plugin */ |
433 | 0 | p = mk_plugin_load(MK_PLUGIN_STATIC, |
434 | 0 | p->shortname, |
435 | 0 | (void *) p, |
436 | 0 | server); |
437 | 0 | if (!p) { |
438 | 0 | continue; |
439 | 0 | } |
440 | 0 | ret = mk_plugin_init(server->api, p, server); |
441 | 0 | if (ret == -1) { |
442 | | /* Free plugin, do not register, error initializing */ |
443 | 0 | mk_warn("Plugin initialization failed: %s", p->shortname); |
444 | 0 | mk_plugin_unregister(p); |
445 | 0 | continue; |
446 | 0 | } |
447 | 0 | else if (ret == -2) { |
448 | | /* Do not register, just skip it */ |
449 | 0 | mk_plugin_unregister(p); |
450 | 0 | continue; |
451 | 0 | } |
452 | 0 | } |
453 | | |
454 | | /* In case there are not dynamic plugins */ |
455 | 0 | if (!server->conf_plugin_load) { |
456 | 0 | return; |
457 | 0 | } |
458 | | |
459 | | /* Read configuration file */ |
460 | 0 | path = mk_mem_alloc_z(1024); |
461 | 0 | snprintf(path, 1024, "%s/%s", server->path_conf_root, |
462 | 0 | server->conf_plugin_load); |
463 | 0 | ret = mk_file_get_info(path, &f_info, MK_FILE_READ); |
464 | 0 | if (ret == -1 || f_info.is_file == MK_FALSE) { |
465 | 0 | snprintf(path, 1024, "%s", server->conf_plugin_load); |
466 | 0 | } |
467 | |
|
468 | 0 | cnf = mk_rconf_open(path); |
469 | 0 | if (!cnf) { |
470 | 0 | mk_warn("No dynamic plugins loaded."); |
471 | 0 | mk_mem_free(path); |
472 | 0 | return; |
473 | 0 | } |
474 | | |
475 | | /* Read section 'PLUGINS' */ |
476 | 0 | section = mk_rconf_section_get(cnf, "PLUGINS"); |
477 | 0 | if (!section) { |
478 | 0 | exit(EXIT_FAILURE); |
479 | 0 | } |
480 | | |
481 | | /* Read key entries */ |
482 | 0 | mk_list_foreach_safe(head, htmp, §ion->entries) { |
483 | 0 | entry = mk_list_entry(head, struct mk_rconf_entry, _head); |
484 | 0 | if (strcasecmp(entry->key, "Load") == 0) { |
485 | | |
486 | | /* Get plugin 'shortname' */ |
487 | 0 | tmp = memrchr(entry->val, '-', strlen(entry->val)); |
488 | 0 | ++tmp; |
489 | 0 | memset(shortname, '\0', sizeof(shortname) - 1); |
490 | 0 | strncpy(shortname, tmp, strlen(tmp) - 3); |
491 | | |
492 | | /* Load the dynamic plugin */ |
493 | 0 | p = mk_plugin_load(MK_PLUGIN_DYNAMIC, |
494 | 0 | shortname, |
495 | 0 | entry->val, |
496 | 0 | server); |
497 | 0 | if (!p) { |
498 | 0 | mk_warn("Invalid plugin '%s'", entry->val); |
499 | 0 | continue; |
500 | 0 | } |
501 | | |
502 | 0 | ret = mk_plugin_init(server->api, p, server); |
503 | 0 | if (ret < 0) { |
504 | | /* Free plugin, do not register */ |
505 | 0 | MK_TRACE("Unregister plugin '%s'", p->shortname); |
506 | 0 | mk_plugin_unregister(p); |
507 | 0 | continue; |
508 | 0 | } |
509 | 0 | } |
510 | 0 | } |
511 | | |
512 | | /* Look for plugins thread key data */ |
513 | 0 | mk_plugin_preworker_calls(server); |
514 | 0 | mk_vhost_map_handlers(server); |
515 | 0 | mk_mem_free(path); |
516 | 0 | mk_rconf_free(cnf); |
517 | 0 | } |
518 | | |
519 | | static void mk_plugin_exit_stages(struct mk_plugin *p) |
520 | 0 | { |
521 | 0 | struct mk_list *tmp; |
522 | 0 | struct mk_list *head; |
523 | 0 | struct mk_plugin_stage *st; |
524 | |
|
525 | 0 | mk_list_foreach_safe(head, tmp, &p->stage_list) { |
526 | 0 | st = mk_list_entry(head, struct mk_plugin_stage, _parent_head); |
527 | | |
528 | | /* remove from direct config->stageN head list */ |
529 | 0 | mk_list_del(&st->_head); |
530 | | |
531 | | /* remove from plugin->stage_lists */ |
532 | 0 | mk_list_del(&st->_parent_head); |
533 | 0 | mk_mem_free(st); |
534 | 0 | } |
535 | 0 | } |
536 | | |
537 | | /* Invoke all plugins 'exit' hook and free resources by the plugin interface */ |
538 | | void mk_plugin_exit_all(struct mk_server *server) |
539 | 0 | { |
540 | 0 | struct mk_plugin *plugin; |
541 | 0 | struct mk_list *head, *tmp; |
542 | | |
543 | | /* Plugins */ |
544 | 0 | mk_list_foreach(head, &server->plugins) { |
545 | 0 | plugin = mk_list_entry(head, struct mk_plugin, _head); |
546 | 0 | plugin->exit_plugin(plugin); |
547 | 0 | } |
548 | | |
549 | | /* Plugin interface it self */ |
550 | 0 | mk_list_foreach_safe(head, tmp, &server->plugins) { |
551 | 0 | plugin = mk_list_entry(head, struct mk_plugin, _head); |
552 | 0 | mk_list_del(&plugin->_head); |
553 | 0 | mk_plugin_exit_stages(plugin); |
554 | |
|
555 | 0 | if (plugin->load_type == MK_PLUGIN_DYNAMIC) { |
556 | 0 | mk_mem_free(plugin->path); |
557 | | #ifdef _WIN32 |
558 | | FreeLibrary((HMODULE)plugin->handler); |
559 | | #else |
560 | 0 | dlclose(plugin ->handler); |
561 | 0 | #endif |
562 | 0 | } |
563 | 0 | else if (plugin->load_type == MK_PLUGIN_STATIC) { |
564 | 0 | if (plugin->network != NULL) { |
565 | 0 | mk_mem_free(plugin->network); |
566 | 0 | } |
567 | |
|
568 | 0 | mk_mem_free(plugin); |
569 | 0 | } |
570 | 0 | } |
571 | |
|
572 | 0 | mk_mem_free(server->api); |
573 | 0 | mk_mem_free(plg_stagemap); |
574 | 0 | } |
575 | | |
576 | | /* |
577 | | * When a worker is exiting, it invokes this function to release any plugin |
578 | | * associated data. |
579 | | */ |
580 | | void mk_plugin_exit_worker() |
581 | 0 | { |
582 | 0 | } |
583 | | |
584 | | /* This function is called by every created worker |
585 | | * for plugins which need to set some data under a thread |
586 | | * context |
587 | | */ |
588 | | void mk_plugin_core_process(struct mk_server *server) |
589 | 0 | { |
590 | 0 | struct mk_plugin *node; |
591 | 0 | struct mk_list *head; |
592 | |
|
593 | 0 | mk_list_foreach(head, &server->plugins) { |
594 | 0 | node = mk_list_entry(head, struct mk_plugin, _head); |
595 | | |
596 | | /* Init plugin */ |
597 | 0 | if (node->master_init) { |
598 | 0 | node->master_init(server); |
599 | 0 | } |
600 | 0 | } |
601 | 0 | } |
602 | | |
603 | | /* This function is called by every created worker |
604 | | * for plugins which need to set some data under a thread |
605 | | * context |
606 | | */ |
607 | | void mk_plugin_core_thread(struct mk_server *server) |
608 | 0 | { |
609 | |
|
610 | 0 | struct mk_plugin *node; |
611 | 0 | struct mk_list *head; |
612 | |
|
613 | 0 | mk_list_foreach(head, &server->plugins) { |
614 | 0 | node = mk_list_entry(head, struct mk_plugin, _head); |
615 | | |
616 | | /* Init plugin thread context */ |
617 | 0 | if (node->worker_init) { |
618 | 0 | node->worker_init(server); |
619 | 0 | } |
620 | 0 | } |
621 | 0 | } |
622 | | |
623 | | /* This function is called by Monkey *outside* of the |
624 | | * thread context for plugins, so here's the right |
625 | | * place to set pthread keys or similar |
626 | | */ |
627 | | void mk_plugin_preworker_calls(struct mk_server *server) |
628 | 0 | { |
629 | 0 | int ret; |
630 | 0 | struct mk_plugin *node; |
631 | 0 | struct mk_list *head; |
632 | |
|
633 | 0 | mk_list_foreach(head, &server->plugins) { |
634 | 0 | node = mk_list_entry(head, struct mk_plugin, _head); |
635 | | |
636 | | /* Init pthread keys */ |
637 | 0 | if (node->thread_key) { |
638 | 0 | MK_TRACE("[%s] Set thread key", node->shortname); |
639 | |
|
640 | 0 | ret = pthread_key_create(node->thread_key, NULL); |
641 | 0 | if (ret != 0) { |
642 | 0 | mk_err("Plugin Error: could not create key for %s", |
643 | 0 | node->shortname); |
644 | 0 | } |
645 | 0 | } |
646 | 0 | } |
647 | 0 | } |
648 | | |
649 | | int mk_plugin_http_error(int http_status, struct mk_http_session *cs, |
650 | | struct mk_http_request *sr, |
651 | | struct mk_plugin *plugin) |
652 | 0 | { |
653 | 0 | return mk_http_error(http_status, cs, sr, plugin->server_ctx); |
654 | 0 | } |
655 | | |
656 | | |
657 | | int mk_plugin_http_request_end(struct mk_plugin *plugin, |
658 | | struct mk_http_session *cs, int close) |
659 | 0 | { |
660 | 0 | int ret; |
661 | 0 | int con; |
662 | 0 | struct mk_http_request *sr; |
663 | 0 | struct mk_server *server = plugin->server_ctx; |
664 | |
|
665 | 0 | MK_TRACE("[FD %i] PLUGIN HTTP REQUEST END", cs->socket); |
666 | |
|
667 | 0 | cs->status = MK_REQUEST_STATUS_INCOMPLETE; |
668 | 0 | if (mk_list_is_empty(&cs->request_list) == 0) { |
669 | 0 | MK_TRACE("[FD %i] Tried to end non-existing request.", cs->socket); |
670 | 0 | return -1; |
671 | 0 | } |
672 | | |
673 | 0 | sr = mk_list_entry_last(&cs->request_list, struct mk_http_request, _head); |
674 | 0 | mk_plugin_stage_run_40(cs, sr, server); |
675 | |
|
676 | 0 | if (close == MK_TRUE) { |
677 | 0 | cs->close_now = MK_TRUE; |
678 | 0 | } |
679 | | |
680 | | /* Let's check if we should ask to finalize the connection or not */ |
681 | 0 | ret = mk_http_request_end(cs, server); |
682 | 0 | MK_TRACE("[FD %i] HTTP session end = %i", cs->socket, ret); |
683 | 0 | if (ret < 0) { |
684 | 0 | con = mk_sched_event_close(cs->conn, mk_sched_get_thread_conf(), |
685 | 0 | MK_EP_SOCKET_DONE, server); |
686 | 0 | if (con != 0) { |
687 | 0 | return con; |
688 | 0 | } |
689 | 0 | else { |
690 | 0 | return -1; |
691 | 0 | } |
692 | 0 | } |
693 | | |
694 | 0 | return ret; |
695 | 0 | } |
696 | | |
697 | | /* Plugin epoll event handlers |
698 | | * --------------------------- |
699 | | * this functions are called by connection.c functions as mk_conn_read(), |
700 | | * mk_conn_write(),mk_conn_error(), mk_conn_close() and mk_conn_timeout(). |
701 | | * |
702 | | * Return Values: |
703 | | * ------------- |
704 | | * MK_PLUGIN_RET_EVENT_NOT_ME: There's no plugin hook associated |
705 | | */ |
706 | | |
707 | | void mk_plugin_event_bad_return(const char *hook, int ret) |
708 | 0 | { |
709 | 0 | mk_err("[%s] Not allowed return value %i", hook, ret); |
710 | 0 | } |
711 | | |
712 | | int mk_plugin_time_now_unix(struct mk_server *server) |
713 | 0 | { |
714 | 0 | return server->clock_context->log_current_utime; |
715 | 0 | } |
716 | | |
717 | | mk_ptr_t *mk_plugin_time_now_human(struct mk_server *server) |
718 | 0 | { |
719 | 0 | return &server->clock_context->log_current_time; |
720 | 0 | } |
721 | | |
722 | | int mk_plugin_sched_remove_client(int socket, struct mk_server *server) |
723 | 0 | { |
724 | 0 | struct mk_sched_conn *conn; |
725 | 0 | struct mk_sched_worker *sched; |
726 | |
|
727 | 0 | MK_TRACE("[FD %i] remove client", socket); |
728 | |
|
729 | 0 | sched = mk_sched_get_thread_conf(); |
730 | 0 | conn = mk_sched_get_connection(sched, socket); |
731 | 0 | if (!conn) { |
732 | 0 | return -1; |
733 | 0 | } |
734 | | |
735 | 0 | return mk_sched_remove_client(conn, sched, server); |
736 | 0 | } |
737 | | |
738 | | int mk_plugin_header_prepare(struct mk_plugin *plugin, |
739 | | struct mk_http_session *cs, |
740 | | struct mk_http_request *sr) |
741 | 0 | { |
742 | 0 | return mk_header_prepare(cs, sr, plugin->server_ctx); |
743 | 0 | } |
744 | | |
745 | | |
746 | | int mk_plugin_header_add(struct mk_http_request *sr, char *row, int len) |
747 | 0 | { |
748 | 0 | mk_bug(!sr); |
749 | | |
750 | 0 | if (!sr->headers._extra_rows) { |
751 | | /* |
752 | | * We allocate space for a fixed number of IOV entries: |
753 | | * |
754 | | * MK_PLUGIN_HEADER_EXTRA_ROWS = X |
755 | | * |
756 | | * we use (MK_PLUGIN_HEADER_EXTRA_ROWS * 2) thinking in an ending CRLF |
757 | | */ |
758 | 0 | sr->headers._extra_rows = mk_iov_create(MK_PLUGIN_HEADER_EXTRA_ROWS * 2, 0); |
759 | 0 | mk_bug(!sr->headers._extra_rows); |
760 | 0 | } |
761 | | |
762 | 0 | mk_iov_add(sr->headers._extra_rows, row, len, |
763 | 0 | MK_FALSE); |
764 | 0 | mk_iov_add(sr->headers._extra_rows, |
765 | 0 | mk_iov_crlf.data, mk_iov_crlf.len, |
766 | 0 | MK_FALSE); |
767 | 0 | return 0; |
768 | 0 | } |
769 | | |
770 | | struct mk_sched_worker *mk_plugin_sched_get_thread_conf() |
771 | 0 | { |
772 | 0 | return MK_TLS_GET(mk_tls_sched_worker_node); |
773 | 0 | } |
774 | | |
775 | | struct mk_plugin *mk_plugin_cap(char cap, struct mk_server *server) |
776 | 0 | { |
777 | 0 | struct mk_list *head; |
778 | 0 | struct mk_plugin *plugin; |
779 | |
|
780 | 0 | mk_list_foreach(head, &server->plugins) { |
781 | 0 | plugin = mk_list_entry(head, struct mk_plugin, _head); |
782 | 0 | if (plugin->capabilities & cap) { |
783 | 0 | return plugin; |
784 | 0 | } |
785 | 0 | } |
786 | | |
787 | 0 | return NULL; |
788 | 0 | } |
789 | | |
790 | | struct mk_vhost_handler_param *mk_handler_param_get(int id, |
791 | | struct mk_list *params) |
792 | 0 | { |
793 | 0 | int i = 0; |
794 | 0 | struct mk_list *head; |
795 | |
|
796 | 0 | mk_list_foreach(head, params) { |
797 | 0 | if (i == id) { |
798 | 0 | return mk_list_entry(head, struct mk_vhost_handler_param, _head); |
799 | 0 | } |
800 | 0 | i++; |
801 | 0 | } |
802 | | |
803 | 0 | return NULL; |
804 | 0 | } |