Add some TRACE messages
[MonkeyD.git] / src / plugin.c
blobf4f5ff8c946630b6281c9af1a65de1de70320e01
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 /* Monkey HTTP Daemon
4 * ------------------
5 * Copyright (C) 2001-2010, Eduardo Silva P.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Library General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 #include <string.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
28 #include <dlfcn.h>
29 #include <err.h>
31 #include "config.h"
32 #include "plugin.h"
33 #include "monkey.h"
34 #include "request.h"
35 #include "scheduler.h"
36 #include "utils.h"
37 #include "str.h"
38 #include "file.h"
39 #include "header.h"
40 #include "memory.h"
41 #include "iov.h"
42 #include "epoll.h"
44 void *mk_plugin_load(char *path)
46 void *handle;
48 handle = dlopen(path, RTLD_LAZY);
49 if (!handle) {
50 fprintf(stderr, "Error during dlopen(): %s\n", dlerror());
51 exit(1);
53 return handle;
56 void *mk_plugin_load_symbol(void *handler, const char *symbol)
58 char *err;
59 void *s;
61 dlerror();
62 s = dlsym(handler, symbol);
63 if ((err = dlerror()) != NULL) {
64 return NULL;
67 return s;
70 void mk_plugin_register_add_to_stage(struct plugin **st, struct plugin *p)
72 struct plugin *list;
74 if (!*st) {
75 *st = p;
76 return;
79 list = *st;
81 while (list->next) {
82 list = list->next;
85 list->next = p;
88 void mk_plugin_register_stages(struct plugin *p)
90 struct plugin_list *new, *list;
92 /* Main plugin list */
93 new = mk_mem_malloc(sizeof(struct plugin_list));
94 new->p = p;
95 new->next = NULL;
97 if (!plg_list) {
98 plg_list = new;
100 else {
101 list = plg_list;
102 while (list->next) {
103 list = list->next;
105 list->next = new;
108 /* Assign plugin to stages */
109 if (*p->stages & MK_PLUGIN_STAGE_00) {
110 mk_plugin_register_add_to_stage(&config->plugins->stage_00, p);
113 if (*p->stages & MK_PLUGIN_STAGE_10) {
114 mk_plugin_register_add_to_stage(&config->plugins->stage_10, p);
117 if (*p->stages & MK_PLUGIN_STAGE_20) {
118 mk_plugin_register_add_to_stage(&config->plugins->stage_20, p);
121 if (*p->stages & MK_PLUGIN_STAGE_30) {
122 mk_plugin_register_add_to_stage(&config->plugins->stage_30, p);
125 if (*p->stages & MK_PLUGIN_STAGE_40) {
126 mk_plugin_register_add_to_stage(&config->plugins->stage_40, p);
129 if (*p->stages & MK_PLUGIN_STAGE_50) {
130 mk_plugin_register_add_to_stage(&config->plugins->stage_50, p);
133 if (*p->stages & MK_PLUGIN_STAGE_60) {
134 mk_plugin_register_add_to_stage(&config->plugins->stage_60, p);
138 void *mk_plugin_register(void *handler, char *path)
140 struct plugin *p;
142 p = mk_mem_malloc_z(sizeof(struct plugin));
143 p->shortname = mk_plugin_load_symbol(handler, "_shortname");
144 p->name = mk_plugin_load_symbol(handler, "_name");
145 p->version = mk_plugin_load_symbol(handler, "_version");
146 p->path = mk_string_dup(path);
147 p->handler = handler;
148 p->stages =
149 (mk_plugin_stage_t *) mk_plugin_load_symbol(handler, "_stages");
151 /* Plugin external functions */
152 p->call_init = (int (*)()) mk_plugin_load_symbol(handler,
153 "_mk_plugin_init");
155 p->call_worker_init = (int (*)()) mk_plugin_load_symbol(handler,
156 "_mk_plugin_worker_init");
158 p->call_stage_10 = (int (*)())
159 mk_plugin_load_symbol(handler, "_mk_plugin_stage_00");
161 p->call_stage_10 = (int (*)())
162 mk_plugin_load_symbol(handler, "_mk_plugin_stage_10");
164 p->call_stage_20 = (int (*)())
165 mk_plugin_load_symbol(handler, "_mk_plugin_stage_20");
167 p->call_stage_30 = (int (*)())
168 mk_plugin_load_symbol(handler, "_mk_plugin_stage_30");
170 p->call_stage_40 = (int (*)())
171 mk_plugin_load_symbol(handler, "_mk_plugin_stage_40");
173 p->call_stage_40_event_read = (int (*)())
174 mk_plugin_load_symbol(handler, "_mk_plugin_stage_40_event_read");
176 p->call_stage_40_event_write = (int (*)())
177 mk_plugin_load_symbol(handler, "_mk_plugin_stage_40_event_write");
179 p->thread_key = (pthread_key_t) mk_plugin_load_symbol(handler, "_mk_plugin_data");
181 p->next = NULL;
183 if (!p->name || !p->version || !p->stages) {
184 mk_mem_free(p);
185 return NULL;
188 mk_plugin_register_stages(p);
189 return p;
192 void mk_plugin_init()
194 char *path;
195 void *handle;
196 struct plugin *p;
197 struct plugin_api *api;
198 struct plugin_list *plist;
199 struct mk_config *cnf;
201 api = mk_mem_malloc_z(sizeof(struct plugin_api));
203 /* Setup and connections list */
204 api->config = config;
205 api->sched_list = &sched_list;
207 /* API plugins funcions */
208 api->mem_alloc = (void *) mk_mem_malloc;
209 api->mem_alloc_z = (void *) mk_mem_malloc_z;
210 api->mem_free = (void *) mk_mem_free;
211 api->str_build = (void *) m_build_buffer;
212 api->str_dup = (void *) mk_string_dup;
213 api->str_search = (void *) mk_string_search;
214 api->str_search_n = (void *) mk_string_search_n;
215 api->str_copy_substr = (void *) mk_string_copy_substr;
216 api->str_split_line = (void *) mk_string_split_line;
217 api->file_to_buffer = (void *) mk_file_to_buffer;
218 api->file_get_info = (void *) mk_file_get_info;
219 api->header_send = (void *) mk_header_send;
220 api->iov_create = (void *) mk_iov_create;
221 api->iov_free = (void *) mk_iov_free;
222 api->iov_add_entry = (void *) mk_iov_add_entry;
223 api->iov_set_entry = (void *) mk_iov_set_entry;
224 api->iov_send = (void *) mk_iov_send;
225 api->iov_print = (void *) mk_iov_print;
226 api->pointer_set = (void *) mk_pointer_set;
227 api->pointer_print = (void *) mk_pointer_print;
228 api->plugin_load_symbol = (void *) mk_plugin_load_symbol;
229 api->socket_cork_flag = (void *) mk_socket_set_cork_flag;
230 api->socket_connect = (void *) mk_socket_connect;
231 api->socket_set_tcp_nodelay = (void *) mk_socket_set_tcp_nodelay;
232 api->socket_set_nonblocking = (void *) mk_socket_set_nonblocking;
233 api->socket_create = (void *) mk_socket_create;
234 api->config_create = (void *) mk_config_create;
235 api->config_free = (void *) mk_config_free;
236 api->config_getval = (void *) mk_config_getval;
237 api->sched_get_connection = (void *) mk_sched_get_connection;
238 api->event_add = (void *) mk_plugin_event_add;
239 api->event_socket_change_mode = (void *) mk_plugin_event_socket_change_mode;
241 #ifdef TRACE
242 api->trace = (void *) mk_utils_trace;
243 #endif
245 path = mk_mem_malloc_z(1024);
246 snprintf(path, 1024, "%s/%s", config->serverconf, MK_PLUGIN_LOAD);
248 /* Read configuration file */
249 cnf = mk_config_create(path);
251 while (cnf) {
252 if (strcasecmp(cnf->key, "LoadPlugin") == 0) {
253 handle = mk_plugin_load(cnf->val);
254 p = mk_plugin_register(handle, cnf->val);
255 if (!p) {
256 fprintf(stderr, "Plugin error: %s", cnf->val);
257 dlclose(handle);
259 else {
260 char *plugin_confdir = 0;
261 unsigned long len;
263 m_build_buffer(&plugin_confdir,
264 &len,
265 "%s/plugins/%s/",
266 config->serverconf, p->shortname);
268 p->call_init(&api, plugin_confdir);
271 cnf = cnf->next;
274 api->plugins = plg_list;
275 plist = plg_list;
276 mk_mem_free(path);
279 int mk_plugin_stage_run(mk_plugin_stage_t stage,
280 unsigned int socket,
281 struct sched_connection *conx,
282 struct client_request *cr, struct request *sr)
284 int ret;
285 struct plugin *p;
287 if (stage & MK_PLUGIN_STAGE_10) {
288 p = config->plugins->stage_10;
289 while (p) {
290 #ifdef TRACE
291 MK_TRACE("[%s] STAGE 10", p->shortname);
292 #endif
293 p->call_stage_10();
294 p = p->next;
297 if (stage & MK_PLUGIN_STAGE_20) {
298 p = config->plugins->stage_20;
299 while (p) {
300 #ifdef TRACE
301 MK_TRACE("[%s] STAGE 20", p->shortname);
302 #endif
303 ret = p->call_stage_20(socket, conx, cr);
304 switch (ret) {
305 case MK_PLUGIN_RET_CLOSE_CONX:
306 #ifdef TRACE
307 MK_TRACE("return MK_PLUGIN_RET_CLOSE_CONX");
308 #endif
309 return MK_PLUGIN_RET_CLOSE_CONX;
312 p = p->next;
316 if (stage & MK_PLUGIN_STAGE_30) {
317 p = config->plugins->stage_30;
318 while (p) {
319 #ifdef TRACE
320 MK_TRACE("[%s] STAGE 30", p->shortname);
321 #endif
322 ret = p->call_stage_30(cr, sr);
323 switch (ret) {
324 case MK_PLUGIN_RET_CLOSE_CONX:
325 return MK_PLUGIN_RET_CLOSE_CONX;
328 p = p->next;
332 /* Object handler */
333 if (stage & MK_PLUGIN_STAGE_40) {
334 /* The request just arrived and is required to check who can
335 * handle it */
336 if (!sr->handled_by){
337 p = config->plugins->stage_40;
338 while (p) {
339 /* Call stage */
340 #ifdef TRACE
341 MK_TRACE("[%s] STAGE 40", p->shortname);
342 #endif
343 ret = p->call_stage_40(p, cr, sr);
345 switch (ret) {
346 case MK_PLUGIN_RET_NOT_ME:
347 break;
348 case MK_PLUGIN_RET_CONTINUE:
349 return MK_PLUGIN_RET_CONTINUE;
351 p = p->next;
356 return -1;
359 void mk_plugin_request_handler_add(struct request *sr, struct plugin *p)
361 if (!sr->handled_by) {
362 sr->handled_by = p;
363 return;
367 void mk_plugin_request_handler_del(struct request *sr, struct plugin *p)
369 if (!sr->handled_by) {
370 return;
373 mk_mem_free(sr->handled_by);
376 /* This function is called by every created worker
377 * for plugins which need to set some data under a thread
378 * context
380 void mk_plugin_worker_startup()
382 struct plugin_list *plg;
384 plg = plg_list;
386 while (plg) {
387 /* Init plugin */
388 if (plg->p->call_worker_init) {
389 plg->p->call_worker_init();
392 plg = plg->next;
396 /* This function is called by Monkey *outside* of the
397 * thread context for plugins, so here's the right
398 * place to set pthread keys or similar
400 void mk_plugin_preworker_calls()
402 int ret;
403 struct plugin_list *plg;
405 plg = plg_list;
407 while (plg) {
408 /* Init pthread keys */
409 if (plg->p->thread_key) {
410 ret = pthread_key_create(&plg->p->thread_key, NULL);
411 if (ret != 0) {
412 printf("\nPlugin Error: could not create key for %s",
413 plg->p->shortname);
414 fflush(stdout);
415 exit(1);
418 plg = plg->next;
422 int mk_plugin_event_add(int socket, struct plugin *handler,
423 struct client_request *cr,
424 struct request *sr)
426 struct sched_list_node *sched;
427 struct plugin_event *list;
428 struct plugin_event *aux;
429 struct plugin_event *event;
431 sched = mk_sched_get_thread_conf();
433 if (!sched || !handler || !cr || !sr) {
434 return -1;
437 /* Event node (this list exist at thread level */
438 event = mk_mem_malloc(sizeof(struct plugin_event));
439 event->socket = socket;
440 event->handler = handler;
441 event->cr = cr;
442 event->sr = sr;
443 event->next = NULL;
445 /* Get thread event list */
446 list = mk_plugin_event_get_list();
447 if (!list) {
448 mk_plugin_event_set_list(event);
450 else {
451 aux = list;
452 while (aux->next) {
453 aux = aux->next;
456 aux->next = event;
457 mk_plugin_event_set_list(aux);
460 /* The thread event info has been registered, now we need
461 to register the socket involved to the thread epoll array */
462 mk_epoll_add_client(sched->epoll_fd, event->socket,
463 MK_EPOLL_WRITE, MK_EPOLL_BEHAVIOR_TRIGGERED);
464 return 0;
467 int mk_plugin_event_socket_change_mode(int socket, int mode)
469 struct sched_list_node *sched;
471 sched = mk_sched_get_thread_conf();
473 if (!sched) {
474 return -1;
477 return mk_epoll_socket_change_mode(sched->epoll_fd, socket, mode);
480 struct plugin_event *mk_plugin_event_get(int socket)
482 struct plugin_event *event;
484 event = mk_plugin_event_get_list();
486 while (event){
487 if (event->socket == socket) {
488 return event;
491 event = event->next;
494 return NULL;
497 int mk_plugin_event_set_list(struct plugin_event *event)
499 return pthread_setspecific(mk_plugin_event_k, (void *) event);
502 struct plugin_event *mk_plugin_event_get_list()
504 return (struct plugin_event *) pthread_getspecific(mk_plugin_event_k);
508 /* Plugin epoll event handlers
509 * ---------------------------
510 * this functions are called by connection.c functions as mk_conn_read(),
511 * mk_conn_write(),mk_conn_error(), mk_conn_close() and mk_conn_timeout
513 * Return Values:
514 * -------------
515 * MK_PLUGIN_RET_EVENT_NOT_ME: There's no plugin hook associated
518 int mk_plugin_event_read(int socket)
520 struct plugin_event *event;
522 #ifdef TRACE
523 MK_TRACE("Plugin, event read");
524 #endif
526 event = mk_plugin_event_get(socket);
527 if (!event) {
528 return MK_PLUGIN_RET_EVENT_NOT_ME;
531 if (event->handler->call_stage_40_event_read) {
532 event->handler->call_stage_40_event_read(event->cr, event->sr);
535 return MK_PLUGIN_RET_CONTINUE;
538 int mk_plugin_event_write(int socket)
540 struct plugin_event *event;
542 #ifdef TRACE
543 MK_TRACE("Plugin, event write fd %i", socket);
544 #endif
546 event = mk_plugin_event_get(socket);
547 if (!event) {
548 return MK_PLUGIN_RET_EVENT_NOT_ME;
551 if (event->handler->call_stage_40_event_write) {
552 event->handler->call_stage_40_event_write(event->cr, event->sr);
555 return MK_PLUGIN_RET_CONTINUE;
558 int mk_plugin_event_error(int socket)
560 #ifdef TRACE
561 MK_TRACE("Plugin, event error fd %i", socket);
562 #endif
564 return 0;
567 int mk_plugin_event_close(int socket)
570 #ifdef TRACE
571 MK_TRACE("Plugin, event close fd %i", socket);
572 #endif
574 return 0;
577 int mk_plugin_event_timeout(int socket)
580 #ifdef TRACE
581 MK_TRACE("Plugin, event timeout fd %i", socket);
582 #endif
584 return 0;