Minor fixes
[MonkeyD.git] / src / plugin.c
blobe5a84a9fb224035cc428465ba8f3331535df3c4a
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 #ifdef TRACE
185 MK_TRACE("Bad plugin definition: %s", path);
186 #endif
187 mk_mem_free(p);
188 return NULL;
191 mk_plugin_register_stages(p);
192 return p;
195 void mk_plugin_init()
197 char *path;
198 void *handle;
199 struct plugin *p;
200 struct plugin_api *api;
201 struct plugin_list *plist;
202 struct mk_config *cnf;
204 api = mk_mem_malloc_z(sizeof(struct plugin_api));
206 /* Setup and connections list */
207 api->config = config;
208 api->sched_list = &sched_list;
210 /* API plugins funcions */
211 api->mem_alloc = (void *) mk_mem_malloc;
212 api->mem_alloc_z = (void *) mk_mem_malloc_z;
213 api->mem_free = (void *) mk_mem_free;
214 api->str_build = (void *) m_build_buffer;
215 api->str_dup = (void *) mk_string_dup;
216 api->str_search = (void *) mk_string_search;
217 api->str_search_n = (void *) mk_string_search_n;
218 api->str_copy_substr = (void *) mk_string_copy_substr;
219 api->str_split_line = (void *) mk_string_split_line;
220 api->file_to_buffer = (void *) mk_file_to_buffer;
221 api->file_get_info = (void *) mk_file_get_info;
222 api->header_send = (void *) mk_header_send;
223 api->iov_create = (void *) mk_iov_create;
224 api->iov_free = (void *) mk_iov_free;
225 api->iov_add_entry = (void *) mk_iov_add_entry;
226 api->iov_set_entry = (void *) mk_iov_set_entry;
227 api->iov_send = (void *) mk_iov_send;
228 api->iov_print = (void *) mk_iov_print;
229 api->pointer_set = (void *) mk_pointer_set;
230 api->pointer_print = (void *) mk_pointer_print;
231 api->plugin_load_symbol = (void *) mk_plugin_load_symbol;
232 api->socket_cork_flag = (void *) mk_socket_set_cork_flag;
233 api->socket_connect = (void *) mk_socket_connect;
234 api->socket_set_tcp_nodelay = (void *) mk_socket_set_tcp_nodelay;
235 api->socket_set_nonblocking = (void *) mk_socket_set_nonblocking;
236 api->socket_create = (void *) mk_socket_create;
237 api->config_create = (void *) mk_config_create;
238 api->config_free = (void *) mk_config_free;
239 api->config_getval = (void *) mk_config_getval;
240 api->sched_get_connection = (void *) mk_sched_get_connection;
241 api->event_add = (void *) mk_plugin_event_add;
242 api->event_socket_change_mode = (void *) mk_plugin_event_socket_change_mode;
244 #ifdef TRACE
245 api->trace = (void *) mk_utils_trace;
246 #endif
248 path = mk_mem_malloc_z(1024);
249 snprintf(path, 1024, "%s/%s", config->serverconf, MK_PLUGIN_LOAD);
251 /* Read configuration file */
252 cnf = mk_config_create(path);
254 while (cnf) {
255 if (strcasecmp(cnf->key, "LoadPlugin") == 0) {
256 handle = mk_plugin_load(cnf->val);
257 p = mk_plugin_register(handle, cnf->val);
258 if (!p) {
259 fprintf(stderr, "Plugin error: %s", cnf->val);
260 dlclose(handle);
262 else {
263 char *plugin_confdir = 0;
264 unsigned long len;
266 m_build_buffer(&plugin_confdir,
267 &len,
268 "%s/plugins/%s/",
269 config->serverconf, p->shortname);
271 p->call_init(&api, plugin_confdir);
274 cnf = cnf->next;
277 api->plugins = plg_list;
278 plist = plg_list;
279 mk_mem_free(path);
282 int mk_plugin_stage_run(mk_plugin_stage_t stage,
283 unsigned int socket,
284 struct sched_connection *conx,
285 struct client_request *cr, struct request *sr)
287 int ret;
288 struct plugin *p;
290 if (stage & MK_PLUGIN_STAGE_10) {
291 p = config->plugins->stage_10;
292 while (p) {
293 #ifdef TRACE
294 MK_TRACE("[%s] STAGE 10", p->shortname);
295 #endif
296 p->call_stage_10();
297 p = p->next;
301 if (stage & MK_PLUGIN_STAGE_20) {
302 p = config->plugins->stage_20;
303 while (p) {
304 #ifdef TRACE
305 MK_TRACE("[%s] STAGE 20", p->shortname);
306 #endif
307 ret = p->call_stage_20(socket, conx, cr);
308 switch (ret) {
309 case MK_PLUGIN_RET_CLOSE_CONX:
310 #ifdef TRACE
311 MK_TRACE("return MK_PLUGIN_RET_CLOSE_CONX");
312 #endif
313 return MK_PLUGIN_RET_CLOSE_CONX;
316 p = p->next;
320 if (stage & MK_PLUGIN_STAGE_30) {
321 p = config->plugins->stage_30;
322 while (p) {
323 #ifdef TRACE
324 MK_TRACE("[%s] STAGE 30", p->shortname);
325 #endif
326 ret = p->call_stage_30(cr, sr);
327 switch (ret) {
328 case MK_PLUGIN_RET_CLOSE_CONX:
329 return MK_PLUGIN_RET_CLOSE_CONX;
332 p = p->next;
336 /* Object handler */
337 if (stage & MK_PLUGIN_STAGE_40) {
338 /* The request just arrived and is required to check who can
339 * handle it */
340 if (!sr->handled_by){
341 p = config->plugins->stage_40;
342 while (p) {
343 /* Call stage */
344 #ifdef TRACE
345 MK_TRACE("[%s] STAGE 40", p->shortname);
346 #endif
347 ret = p->call_stage_40(p, cr, sr);
349 switch (ret) {
350 case MK_PLUGIN_RET_NOT_ME:
351 break;
352 case MK_PLUGIN_RET_CONTINUE:
353 return MK_PLUGIN_RET_CONTINUE;
355 p = p->next;
360 return -1;
363 void mk_plugin_request_handler_add(struct request *sr, struct plugin *p)
365 if (!sr->handled_by) {
366 sr->handled_by = p;
367 return;
371 void mk_plugin_request_handler_del(struct request *sr, struct plugin *p)
373 if (!sr->handled_by) {
374 return;
377 mk_mem_free(sr->handled_by);
380 /* This function is called by every created worker
381 * for plugins which need to set some data under a thread
382 * context
384 void mk_plugin_worker_startup()
386 struct plugin_list *plg;
388 plg = plg_list;
390 while (plg) {
391 /* Init plugin */
392 if (plg->p->call_worker_init) {
393 plg->p->call_worker_init();
396 plg = plg->next;
400 /* This function is called by Monkey *outside* of the
401 * thread context for plugins, so here's the right
402 * place to set pthread keys or similar
404 void mk_plugin_preworker_calls()
406 int ret;
407 struct plugin_list *plg;
409 plg = plg_list;
411 while (plg) {
412 /* Init pthread keys */
413 if (plg->p->thread_key) {
414 ret = pthread_key_create(&plg->p->thread_key, NULL);
415 if (ret != 0) {
416 printf("\nPlugin Error: could not create key for %s",
417 plg->p->shortname);
418 fflush(stdout);
419 exit(1);
422 plg = plg->next;
426 int mk_plugin_event_add(int socket, struct plugin *handler,
427 struct client_request *cr,
428 struct request *sr)
430 struct sched_list_node *sched;
431 struct plugin_event *list;
432 struct plugin_event *aux;
433 struct plugin_event *event;
435 sched = mk_sched_get_thread_conf();
437 if (!sched || !handler || !cr || !sr) {
438 return -1;
441 /* Event node (this list exist at thread level */
442 event = mk_mem_malloc(sizeof(struct plugin_event));
443 event->socket = socket;
444 event->handler = handler;
445 event->cr = cr;
446 event->sr = sr;
447 event->next = NULL;
449 /* Get thread event list */
450 list = mk_plugin_event_get_list();
451 if (!list) {
452 mk_plugin_event_set_list(event);
454 else {
455 aux = list;
456 while (aux->next) {
457 aux = aux->next;
460 aux->next = event;
461 mk_plugin_event_set_list(aux);
464 /* The thread event info has been registered, now we need
465 to register the socket involved to the thread epoll array */
466 mk_epoll_add_client(sched->epoll_fd, event->socket,
467 MK_EPOLL_WRITE, MK_EPOLL_BEHAVIOR_TRIGGERED);
468 return 0;
471 int mk_plugin_event_socket_change_mode(int socket, int mode)
473 struct sched_list_node *sched;
475 sched = mk_sched_get_thread_conf();
477 if (!sched) {
478 return -1;
481 return mk_epoll_socket_change_mode(sched->epoll_fd, socket, mode);
484 struct plugin_event *mk_plugin_event_get(int socket)
486 struct plugin_event *event;
488 event = mk_plugin_event_get_list();
490 while (event){
491 if (event->socket == socket) {
492 return event;
495 event = event->next;
498 return NULL;
501 int mk_plugin_event_set_list(struct plugin_event *event)
503 return pthread_setspecific(mk_plugin_event_k, (void *) event);
506 struct plugin_event *mk_plugin_event_get_list()
508 return (struct plugin_event *) pthread_getspecific(mk_plugin_event_k);
512 /* Plugin epoll event handlers
513 * ---------------------------
514 * this functions are called by connection.c functions as mk_conn_read(),
515 * mk_conn_write(),mk_conn_error(), mk_conn_close() and mk_conn_timeout
517 * Return Values:
518 * -------------
519 * MK_PLUGIN_RET_EVENT_NOT_ME: There's no plugin hook associated
522 int mk_plugin_event_read(int socket)
524 struct plugin_event *event;
526 #ifdef TRACE
527 MK_TRACE("Plugin, event read FD %i", socket);
528 #endif
530 event = mk_plugin_event_get(socket);
531 if (!event) {
532 return MK_PLUGIN_RET_EVENT_NOT_ME;
535 if (event->handler->call_stage_40_event_read) {
536 event->handler->call_stage_40_event_read(event->cr, event->sr);
539 return MK_PLUGIN_RET_CONTINUE;
542 int mk_plugin_event_write(int socket)
544 struct plugin_event *event;
546 #ifdef TRACE
547 MK_TRACE("Plugin, event write FD %i", socket);
548 #endif
550 event = mk_plugin_event_get(socket);
551 if (!event) {
552 return MK_PLUGIN_RET_EVENT_NOT_ME;
555 if (event->handler->call_stage_40_event_write) {
556 event->handler->call_stage_40_event_write(event->cr, event->sr);
559 return MK_PLUGIN_RET_CONTINUE;
562 int mk_plugin_event_error(int socket)
564 #ifdef TRACE
565 MK_TRACE("Plugin, event error FD %i", socket);
566 #endif
568 return 0;
571 int mk_plugin_event_close(int socket)
574 #ifdef TRACE
575 MK_TRACE("Plugin, event close FD %i", socket);
576 #endif
578 return 0;
581 int mk_plugin_event_timeout(int socket)
584 #ifdef TRACE
585 MK_TRACE("Plugin, event timeout FD %i", socket);
586 #endif
588 return 0;