1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 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.
25 #include <sys/types.h>
35 #include "scheduler.h"
44 void *mk_plugin_load(char *path
)
48 handle
= dlopen(path
, RTLD_LAZY
);
50 fprintf(stderr
, "Error during dlopen(): %s\n", dlerror());
56 void *mk_plugin_load_symbol(void *handler
, const char *symbol
)
62 s
= dlsym(handler
, symbol
);
63 if ((err
= dlerror()) != NULL
) {
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
));
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
)
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
;
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");
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()");
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");
188 p
->thread_key
= (pthread_key_t
) mk_plugin_load_symbol(handler
,
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");
210 if (!p
->name
|| !p
->version
|| !p
->hooks
) {
212 MK_TRACE("Bad plugin definition: %s", path
);
214 mk_mem_free(p
->path
);
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
) {
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",
235 p
->net_io
.send_file
);
237 mk_mem_free(p
->path
);
242 /* Restrict to one NETWORK_IO plugin */
244 plg_netiomap
= &p
->net_io
;
248 "\nError: Loading more than one Network IO Plugin: %s",
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
) {
259 MK_TRACE("Networking IP plugin incomplete: %s", path
);
260 MK_TRACE("Mapped Functions\naddr :%p\nmaxlen :%p",
264 mk_mem_free(p
->path
);
269 /* Restrict to one NETWORK_IP plugin */
271 plg_netipmap
= &p
->net_ip
;
275 "\nError: Loading more than one Network IP Plugin: %s",
281 /* Add Plugin to the end of the list */
282 if (!config
->plugins
) {
286 struct plugin
*plg
= config
->plugins
;
293 mk_plugin_register_stagemap(p
);
297 void mk_plugin_init()
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
));
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
;
330 api
->file_to_buffer
= (void *) mk_file_to_buffer
;
331 api
->file_get_info
= (void *) mk_file_get_info
;
333 api
->header_send
= (void *) mk_header_send
;
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
;
362 api
->trace
= (void *) mk_utils_trace
;
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
);
371 if (strcasecmp(cnf
->key
, "LoadPlugin") == 0) {
372 handle
= mk_plugin_load(cnf
->val
);
373 p
= mk_plugin_register(handle
, cnf
->val
);
375 fprintf(stderr
, "Plugin error: %s\n", cnf
->val
);
379 char *plugin_confdir
= 0;
382 mk_string_build(&plugin_confdir
,
385 config
->serverconf
, p
->shortname
);
387 p
->init(&api
, plugin_confdir
);
394 fprintf(stderr
, "\nError: no Network plugin loaded >:|\n\n");
398 api
->plugins
= config
->plugins
;
402 int mk_plugin_stage_run(mk_plugin_hook_t hook
,
404 struct sched_connection
*conx
,
405 struct client_request
*cr
, struct request
*sr
)
408 struct plugin_stagem
*stm
;
410 if (hook
& MK_PLUGIN_STAGE_10
) {
411 stm
= plg_stagemap
->stage_10
;
414 MK_TRACE("[%s] STAGE 10", stm
->p
->shortname
);
421 if (hook
& MK_PLUGIN_STAGE_20
) {
422 stm
= plg_stagemap
->stage_20
;
425 MK_TRACE("[%s] STAGE 20", stm
->p
->shortname
);
427 ret
= stm
->p
->stage
.s20(socket
, conx
, cr
);
429 case MK_PLUGIN_RET_CLOSE_CONX
:
431 MK_TRACE("return MK_PLUGIN_RET_CLOSE_CONX");
433 return MK_PLUGIN_RET_CLOSE_CONX
;
440 if (hook
& MK_PLUGIN_STAGE_30
) {
441 stm
= plg_stagemap
->stage_30
;
444 MK_TRACE("[%s] STAGE 30", stm
->p
->shortname
);
446 ret
= stm
->p
->stage
.s30(cr
, sr
);
448 case MK_PLUGIN_RET_CLOSE_CONX
:
449 return MK_PLUGIN_RET_CLOSE_CONX
;
457 if (hook
& MK_PLUGIN_STAGE_40
) {
458 /* The request just arrived and is required to check who can
460 if (!sr
->handled_by
){
461 stm
= plg_stagemap
->stage_40
;
465 MK_TRACE("[%s] STAGE 40", stm
->p
->shortname
);
467 ret
= stm
->p
->stage
.s40(stm
->p
, cr
, sr
);
470 case MK_PLUGIN_RET_NOT_ME
:
472 case MK_PLUGIN_RET_CONTINUE
:
473 return MK_PLUGIN_RET_CONTINUE
;
480 if (hook
& MK_PLUGIN_STAGE_50
) {
481 stm
= plg_stagemap
->stage_50
;
484 MK_TRACE("[%s] STAGE 50", stm
->p
->shortname
);
486 ret
= stm
->p
->stage
.s50(cr
, sr
);
488 case MK_PLUGIN_RET_NOT_ME
:
490 case MK_PLUGIN_RET_CONTINUE
:
491 return MK_PLUGIN_RET_CONTINUE
;
500 void mk_plugin_request_handler_add(struct request
*sr
, struct plugin
*p
)
502 if (!sr
->handled_by
) {
508 void mk_plugin_request_handler_del(struct request
*sr
, struct plugin
*p
)
510 if (!sr
->handled_by
) {
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
521 void mk_plugin_worker_startup()
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()
549 /* Init pthread keys */
551 ret
= pthread_key_create(&p
->thread_key
, NULL
);
553 printf("\nPlugin Error: could not create key for %s",
563 int mk_plugin_event_add(int socket
, int mode
,
564 struct plugin
*handler
,
565 struct client_request
*cr
,
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
) {
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
;
587 /* Get thread event list */
588 list
= mk_plugin_event_get_list();
590 mk_plugin_event_set_list(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
);
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();
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();
629 if (event
->socket
== socket
) {
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
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
;
665 MK_TRACE("Plugin, event read FD %i", socket
);
668 event
= mk_plugin_event_get(socket
);
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
;
685 MK_TRACE("Plugin, event write FD %i", socket
);
688 event
= mk_plugin_event_get(socket
);
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
;
705 MK_TRACE("Plugin, event error FD %i", socket
);
708 event
= mk_plugin_event_get(socket
);
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
;
725 MK_TRACE("Plugin, event close FD %i", socket
);
728 event
= mk_plugin_event_get(socket
);
730 return MK_PLUGIN_RET_EVENT_NOT_ME
;
733 if (event
->handler
->event_close
) {
734 return event
->handler
->event_close(event
->cr
, event
->sr
);
740 int mk_plugin_event_timeout(int socket
)
742 struct plugin_event
*event
;
745 MK_TRACE("Plugin, event timeout FD %i", socket
);
748 event
= mk_plugin_event_get(socket
);
750 return MK_PLUGIN_RET_EVENT_NOT_ME
;
753 if (event
->handler
->event_timeout
) {
754 return event
->handler
->event_timeout(event
->cr
, event
->sr
);