Some order in plugin.c. Added more callbacks realted to sockets in the plugin api...
[MonkeyD.git] / src / plugin.c
blob7590638fb0bfd88fd3df8b44c2f8844e7d66e913
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. <edsiper@gmail.com>
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_stagemap_add(struct plugin_stagem **stm, struct plugin *p)
72 struct plugin_stagem *list, *new;
74 new = mk_mem_malloc_z(sizeof(struct plugin_stagem));
75 new->p = p;
76 new->next = NULL;
78 if (!*stm) {
79 *stm = new;
80 return;
83 list = *stm;
85 while (list->next) {
86 list = list->next;
89 list->next = new;
92 void mk_plugin_register_stagemap(struct plugin *p)
94 /* Plugin to stages */
95 if (*p->hooks & MK_PLUGIN_STAGE_10) {
96 mk_plugin_register_stagemap_add(&plg_stagemap->stage_10, p);
99 if (*p->hooks & MK_PLUGIN_STAGE_20) {
100 mk_plugin_register_stagemap_add(&plg_stagemap->stage_20, p);
103 if (*p->hooks & MK_PLUGIN_STAGE_30) {
104 mk_plugin_register_stagemap_add(&plg_stagemap->stage_30, p);
107 if (*p->hooks & MK_PLUGIN_STAGE_40) {
108 mk_plugin_register_stagemap_add(&plg_stagemap->stage_40, p);
111 if (*p->hooks & MK_PLUGIN_STAGE_50) {
112 mk_plugin_register_stagemap_add(&plg_stagemap->stage_50, p);
116 /* Load the plugins and set the library symbols to the
117 * local struct plugin *p node
119 struct plugin *mk_plugin_register(void *handler, char *path)
121 struct plugin *p;
123 p = mk_mem_malloc_z(sizeof(struct plugin));
124 p->shortname = mk_plugin_load_symbol(handler, "_shortname");
125 p->name = mk_plugin_load_symbol(handler, "_name");
126 p->version = mk_plugin_load_symbol(handler, "_version");
127 p->path = mk_string_dup(path);
128 p->handler = handler;
129 p->hooks =
130 (mk_plugin_hook_t *) mk_plugin_load_symbol(handler, "_hooks");
132 /* Mandatory functions */
133 p->init = (int (*)()) mk_plugin_load_symbol(handler, "_mkp_init");
134 p->exit = (int (*)()) mk_plugin_load_symbol(handler, "_mkp_exit");
136 /* Core hooks */
137 p->core.prctx = (int (*)()) mk_plugin_load_symbol(handler,
138 "_mkp_core_prctx()");
139 p->core.thctx = (int (*)()) mk_plugin_load_symbol(handler,
140 "_mkp_core_thctx()");
142 /* Stage hooks */
143 p->stage.s10 = (int (*)())
144 mk_plugin_load_symbol(handler, "_mkp_stage_10");
146 p->stage.s20 = (int (*)())
147 mk_plugin_load_symbol(handler, "_mkp_stage_20");
149 p->stage.s30 = (int (*)())
150 mk_plugin_load_symbol(handler, "_mkp_stage_30");
152 p->stage.s40 = (int (*)())
153 mk_plugin_load_symbol(handler, "_mkp_stage_40");
155 p->stage.s50 = (int (*)())
156 mk_plugin_load_symbol(handler, "_mkp_stage_50");
158 /* Network I/O hooks */
159 p->net_io.accept = (int (*)())
160 mk_plugin_load_symbol(handler, "_mkp_network_io_accept");
162 p->net_io.read = (int (*)())
163 mk_plugin_load_symbol(handler, "_mkp_network_io_read");
165 p->net_io.write = (int (*)())
166 mk_plugin_load_symbol(handler, "_mkp_network_io_write");
168 p->net_io.writev = (int (*)())
169 mk_plugin_load_symbol(handler, "_mkp_network_io_writev");
171 p->net_io.close = (int (*)())
172 mk_plugin_load_symbol(handler, "_mkp_network_io_close");
174 p->net_io.connect = (int (*)())
175 mk_plugin_load_symbol(handler, "_mkp_network_io_connect");
177 p->net_io.send_file = (int (*)())
178 mk_plugin_load_symbol(handler, "_mkp_network_io_send_file");
180 /* Network IP hooks */
181 p->net_ip.addr = (int (*)())
182 mk_plugin_load_symbol(handler, "_mkp_network_ip_addr");
184 p->net_ip.maxlen = (int (*)())
185 mk_plugin_load_symbol(handler, "_mkp_network_ip_maxlen");
187 /* Thread key */
188 p->thread_key = (pthread_key_t) mk_plugin_load_symbol(handler,
189 "_mkp_data");
191 /* Event handlers hooks */
192 p->event_read = (int (*)())
193 mk_plugin_load_symbol(handler, "_mkp_event_read");
195 p->event_write = (int (*)())
196 mk_plugin_load_symbol(handler, "_mkp_event_write");
198 p->event_error = (int (*)())
199 mk_plugin_load_symbol(handler, "_mkp_event_error");
201 p->event_close = (int (*)())
202 mk_plugin_load_symbol(handler, "_mkp_event_close");
204 p->event_timeout = (int (*)())
205 mk_plugin_load_symbol(handler, "_mkp_event_timeout");
207 /* Next ! */
208 p->next = NULL;
210 if (!p->name || !p->version || !p->hooks) {
211 #ifdef TRACE
212 MK_TRACE("Bad plugin definition: %s", path);
213 #endif
214 mk_mem_free(p->path);
215 mk_mem_free(p);
216 return NULL;
219 /* NETWORK_IO Plugin */
220 if (*p->hooks & MK_PLUGIN_NETWORK_IO) {
221 /* Validate mandatory calls */
222 if (!p->net_io.accept || !p->net_io.read || !p->net_io.write ||
223 !p->net_io.writev || !p->net_io.close || !p->net_io.connect ||
224 !p->net_io.send_file) {
225 #ifdef TRACE
226 MK_TRACE("Networking IO plugin incomplete: %s", path);
227 MK_TRACE("Mapped Functions\naccept :%p\nread :%p\n\
228 write :%p\nwritev :%p\nclose :%p\nconnect :%p\nsendfile:%p",
229 p->net_io.accept,
230 p->net_io.read,
231 p->net_io.write,
232 p->net_io.writev,
233 p->net_io.close,
234 p->net_io.connect,
235 p->net_io.send_file);
236 #endif
237 mk_mem_free(p->path);
238 mk_mem_free(p);
239 return NULL;
242 /* Restrict to one NETWORK_IO plugin */
243 if (!plg_netiomap) {
244 plg_netiomap = &p->net_io;
246 else {
247 fprintf(stderr,
248 "\nError: Loading more than one Network IO Plugin: %s",
249 path);
250 exit(1);
254 /* NETWORK_IP Plugin */
255 if (*p->hooks & MK_PLUGIN_NETWORK_IP) {
256 /* Validate mandatory calls */
257 if (!p->net_ip.addr || !p->net_ip.maxlen) {
258 #ifdef TRACE
259 MK_TRACE("Networking IP plugin incomplete: %s", path);
260 MK_TRACE("Mapped Functions\naddr :%p\nmaxlen :%p",
261 p->net_ip.addr,
262 p->net_ip.maxlen);
263 #endif
264 mk_mem_free(p->path);
265 mk_mem_free(p);
266 return NULL;
269 /* Restrict to one NETWORK_IP plugin */
270 if (!plg_netipmap) {
271 plg_netipmap = &p->net_ip;
273 else {
274 fprintf(stderr,
275 "\nError: Loading more than one Network IP Plugin: %s",
276 path);
277 exit(1);
281 /* Add Plugin to the end of the list */
282 if (!config->plugins) {
283 config->plugins = p;
285 else {
286 struct plugin *plg = config->plugins;
287 while(plg->next){
288 plg = plg->next;
290 plg->next = p;
293 mk_plugin_register_stagemap(p);
294 return p;
297 void mk_plugin_init()
299 char *path;
300 void *handle;
301 struct plugin *p;
302 struct plugin_api *api;
303 struct mk_config *cnf;
305 api = mk_mem_malloc_z(sizeof(struct plugin_api));
306 plg_stagemap = mk_mem_malloc_z(sizeof(struct plugin_stagemap));
307 plg_netiomap = NULL;
308 plg_netipmap = NULL;
310 /* Setup and connections list */
311 api->config = config;
312 api->sched_list = &sched_list;
314 /* API plugins funcions */
315 /* Memory callbacks */
316 api->pointer_set = (void *) mk_pointer_set;
317 api->pointer_print = (void *) mk_pointer_print;
318 api->plugin_load_symbol = (void *) mk_plugin_load_symbol;
319 api->mem_alloc = (void *) mk_mem_malloc;
320 api->mem_alloc_z = (void *) mk_mem_malloc_z;
321 api->mem_free = (void *) mk_mem_free;
322 /* String Callbacks */
323 api->str_build = (void *) mk_string_build;
324 api->str_dup = (void *) mk_string_dup;
325 api->str_search = (void *) mk_string_search;
326 api->str_search_n = (void *) mk_string_search_n;
327 api->str_copy_substr = (void *) mk_string_copy_substr;
328 api->str_split_line = (void *) mk_string_split_line;
329 /* File Callbacks */
330 api->file_to_buffer = (void *) mk_file_to_buffer;
331 api->file_get_info = (void *) mk_file_get_info;
332 /* HTTP Callbacks */
333 api->header_send = (void *) mk_header_send;
334 /* IOV callbacks */
335 api->iov_create = (void *) mk_iov_create;
336 api->iov_free = (void *) mk_iov_free;
337 api->iov_add_entry = (void *) mk_iov_add_entry;
338 api->iov_set_entry = (void *) mk_iov_set_entry;
339 api->iov_send = (void *) mk_iov_send;
340 api->iov_print = (void *) mk_iov_print;
341 /* Socket callbacks */
342 api->socket_cork_flag = (void *) mk_socket_set_cork_flag;
343 api->socket_connect = (void *) mk_socket_connect;
344 api->socket_set_tcp_nodelay = (void *) mk_socket_set_tcp_nodelay;
345 api->socket_set_nonblocking = (void *) mk_socket_set_nonblocking;
346 api->socket_create = (void *) mk_socket_create;
347 api->socket_close = (void *) mk_socket_close;
348 api->socket_sendv = (void *) mk_socket_sendv;
349 api->socket_send = (void *) mk_socket_send;
350 api->socket_read = (void *) mk_socket_read;
351 api->socket_send_file = (void *) mk_socket_send_file;
352 /* Config Callbacks */
353 api->config_create = (void *) mk_config_create;
354 api->config_free = (void *) mk_config_free;
355 api->config_getval = (void *) mk_config_getval;
356 /* Scheduler and Event callbacks */
357 api->sched_get_connection = (void *) mk_sched_get_connection;
358 api->event_add = (void *) mk_plugin_event_add;
359 api->event_socket_change_mode = (void *) mk_plugin_event_socket_change_mode;
361 #ifdef TRACE
362 api->trace = (void *) mk_utils_trace;
363 #endif
365 /* Read configuration file */
366 path = mk_mem_malloc_z(1024);
367 snprintf(path, 1024, "%s/%s", config->serverconf, MK_PLUGIN_LOAD);
368 cnf = mk_config_create(path);
370 while (cnf) {
371 if (strcasecmp(cnf->key, "LoadPlugin") == 0) {
372 handle = mk_plugin_load(cnf->val);
373 p = mk_plugin_register(handle, cnf->val);
374 if (!p) {
375 fprintf(stderr, "Plugin error: %s\n", cnf->val);
376 dlclose(handle);
378 else {
379 char *plugin_confdir = 0;
380 unsigned long len;
382 mk_string_build(&plugin_confdir,
383 &len,
384 "%s/plugins/%s/",
385 config->serverconf, p->shortname);
387 p->init(&api, plugin_confdir);
390 cnf = cnf->next;
393 if (!plg_netiomap) {
394 fprintf(stderr, "\nError: no Network plugin loaded >:|\n\n");
395 exit(1);
398 api->plugins = config->plugins;
399 mk_mem_free(path);
402 int mk_plugin_stage_run(mk_plugin_hook_t hook,
403 unsigned int socket,
404 struct sched_connection *conx,
405 struct client_request *cr, struct request *sr)
407 int ret;
408 struct plugin_stagem *stm;
410 if (hook & MK_PLUGIN_STAGE_10) {
411 stm = plg_stagemap->stage_10;
412 while (stm) {
413 #ifdef TRACE
414 MK_TRACE("[%s] STAGE 10", stm->p->shortname);
415 #endif
416 stm->p->stage.s10();
417 stm = stm->next;
421 if (hook & MK_PLUGIN_STAGE_20) {
422 stm = plg_stagemap->stage_20;
423 while (stm) {
424 #ifdef TRACE
425 MK_TRACE("[%s] STAGE 20", stm->p->shortname);
426 #endif
427 ret = stm->p->stage.s20(socket, conx, cr);
428 switch (ret) {
429 case MK_PLUGIN_RET_CLOSE_CONX:
430 #ifdef TRACE
431 MK_TRACE("return MK_PLUGIN_RET_CLOSE_CONX");
432 #endif
433 return MK_PLUGIN_RET_CLOSE_CONX;
436 stm = stm->next;
440 if (hook & MK_PLUGIN_STAGE_30) {
441 stm = plg_stagemap->stage_30;
442 while (stm) {
443 #ifdef TRACE
444 MK_TRACE("[%s] STAGE 30", stm->p->shortname);
445 #endif
446 ret = stm->p->stage.s30(cr, sr);
447 switch (ret) {
448 case MK_PLUGIN_RET_CLOSE_CONX:
449 return MK_PLUGIN_RET_CLOSE_CONX;
452 stm = stm->next;
456 /* Object handler */
457 if (hook & MK_PLUGIN_STAGE_40) {
458 /* The request just arrived and is required to check who can
459 * handle it */
460 if (!sr->handled_by){
461 stm = plg_stagemap->stage_40;
462 while (stm) {
463 /* Call stage */
464 #ifdef TRACE
465 MK_TRACE("[%s] STAGE 40", stm->p->shortname);
466 #endif
467 ret = stm->p->stage.s40(stm->p, cr, sr);
469 switch (ret) {
470 case MK_PLUGIN_RET_NOT_ME:
471 break;
472 case MK_PLUGIN_RET_CONTINUE:
473 return MK_PLUGIN_RET_CONTINUE;
475 stm = stm->next;
480 if (hook & MK_PLUGIN_STAGE_50) {
481 stm = plg_stagemap->stage_50;
482 while (stm) {
483 #ifdef TRACE
484 MK_TRACE("[%s] STAGE 50", stm->p->shortname);
485 #endif
486 ret = stm->p->stage.s50(cr, sr);
487 switch (ret) {
488 case MK_PLUGIN_RET_NOT_ME:
489 break;
490 case MK_PLUGIN_RET_CONTINUE:
491 return MK_PLUGIN_RET_CONTINUE;
493 stm = stm->next;
497 return -1;
500 void mk_plugin_request_handler_add(struct request *sr, struct plugin *p)
502 if (!sr->handled_by) {
503 sr->handled_by = p;
504 return;
508 void mk_plugin_request_handler_del(struct request *sr, struct plugin *p)
510 if (!sr->handled_by) {
511 return;
514 mk_mem_free(sr->handled_by);
517 /* This function is called by every created worker
518 * for plugins which need to set some data under a thread
519 * context
521 void mk_plugin_worker_startup()
523 struct plugin *p;
525 p = config->plugins;
527 while (p) {
528 /* Init plugin */
529 if (p->core.thctx) {
530 p->core.thctx();
533 p = p->next;
537 /* This function is called by Monkey *outside* of the
538 * thread context for plugins, so here's the right
539 * place to set pthread keys or similar
541 void mk_plugin_preworker_calls()
543 int ret;
544 struct plugin *p;
546 p = config->plugins;
548 while (p) {
549 /* Init pthread keys */
550 if (p->thread_key) {
551 ret = pthread_key_create(&p->thread_key, NULL);
552 if (ret != 0) {
553 printf("\nPlugin Error: could not create key for %s",
554 p->shortname);
555 fflush(stdout);
556 exit(1);
559 p = p->next;
563 int mk_plugin_event_add(int socket, int mode,
564 struct plugin *handler,
565 struct client_request *cr,
566 struct request *sr)
568 struct sched_list_node *sched;
569 struct plugin_event *list;
570 struct plugin_event *aux;
571 struct plugin_event *event;
573 sched = mk_sched_get_thread_conf();
575 if (!sched || !handler || !cr || !sr) {
576 return -1;
579 /* Event node (this list exist at thread level */
580 event = mk_mem_malloc(sizeof(struct plugin_event));
581 event->socket = socket;
582 event->handler = handler;
583 event->cr = cr;
584 event->sr = sr;
585 event->next = NULL;
587 /* Get thread event list */
588 list = mk_plugin_event_get_list();
589 if (!list) {
590 mk_plugin_event_set_list(event);
592 else {
593 aux = list;
594 while (aux->next) {
595 aux = aux->next;
598 aux->next = event;
599 mk_plugin_event_set_list(aux);
602 /* The thread event info has been registered, now we need
603 to register the socket involved to the thread epoll array */
604 mk_epoll_add(sched->epoll_fd, event->socket,
605 mode, MK_EPOLL_BEHAVIOR_DEFAULT);
606 return 0;
609 int mk_plugin_event_socket_change_mode(int socket, int mode)
611 struct sched_list_node *sched;
613 sched = mk_sched_get_thread_conf();
615 if (!sched) {
616 return -1;
619 return mk_epoll_change_mode(sched->epoll_fd, socket, mode);
622 struct plugin_event *mk_plugin_event_get(int socket)
624 struct plugin_event *event;
626 event = mk_plugin_event_get_list();
628 while (event){
629 if (event->socket == socket) {
630 return event;
633 event = event->next;
636 return NULL;
639 int mk_plugin_event_set_list(struct plugin_event *event)
641 return pthread_setspecific(mk_plugin_event_k, (void *) event);
644 struct plugin_event *mk_plugin_event_get_list()
646 return (struct plugin_event *) pthread_getspecific(mk_plugin_event_k);
650 /* Plugin epoll event handlers
651 * ---------------------------
652 * this functions are called by connection.c functions as mk_conn_read(),
653 * mk_conn_write(),mk_conn_error(), mk_conn_close() and mk_conn_timeout
655 * Return Values:
656 * -------------
657 * MK_PLUGIN_RET_EVENT_NOT_ME: There's no plugin hook associated
660 int mk_plugin_event_read(int socket)
662 struct plugin_event *event;
664 #ifdef TRACE
665 MK_TRACE("Plugin, event read FD %i", socket);
666 #endif
668 event = mk_plugin_event_get(socket);
669 if (!event) {
670 return MK_PLUGIN_RET_EVENT_NOT_ME;
673 if (event->handler->event_read) {
674 return event->handler->event_read(event->cr, event->sr);
677 return MK_PLUGIN_RET_CONTINUE;
680 int mk_plugin_event_write(int socket)
682 struct plugin_event *event;
684 #ifdef TRACE
685 MK_TRACE("Plugin, event write FD %i", socket);
686 #endif
688 event = mk_plugin_event_get(socket);
689 if (!event) {
690 return MK_PLUGIN_RET_EVENT_NOT_ME;
693 if (event->handler->event_write) {
694 return event->handler->event_write(event->cr, event->sr);
697 return MK_PLUGIN_RET_CONTINUE;
700 int mk_plugin_event_error(int socket)
702 struct plugin_event *event;
704 #ifdef TRACE
705 MK_TRACE("Plugin, event error FD %i", socket);
706 #endif
708 event = mk_plugin_event_get(socket);
709 if (!event) {
710 return MK_PLUGIN_RET_EVENT_NOT_ME;
713 if (event->handler->event_error) {
714 event->handler->event_error(event->cr, event->sr);
717 return MK_PLUGIN_RET_CONTINUE;
720 int mk_plugin_event_close(int socket)
722 struct plugin_event *event;
724 #ifdef TRACE
725 MK_TRACE("Plugin, event close FD %i", socket);
726 #endif
728 event = mk_plugin_event_get(socket);
729 if (!event) {
730 return MK_PLUGIN_RET_EVENT_NOT_ME;
733 if (event->handler->event_close) {
734 return event->handler->event_close(event->cr, event->sr);
737 return 0;
740 int mk_plugin_event_timeout(int socket)
742 struct plugin_event *event;
744 #ifdef TRACE
745 MK_TRACE("Plugin, event timeout FD %i", socket);
746 #endif
748 event = mk_plugin_event_get(socket);
749 if (!event) {
750 return MK_PLUGIN_RET_EVENT_NOT_ME;
753 if (event->handler->event_timeout) {
754 return event->handler->event_timeout(event->cr, event->sr);
757 return 0;