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>
32 #include "connection.h"
36 #include "scheduler.h"
48 void *mk_plugin_load(char *path
)
52 handle
= dlopen(path
, RTLD_LAZY
);
54 fprintf(stderr
, "Error during dlopen(): %s\n", dlerror());
60 void *mk_plugin_load_symbol(void *handler
, const char *symbol
)
66 s
= dlsym(handler
, symbol
);
67 if ((err
= dlerror()) != NULL
) {
74 void mk_plugin_register_stagemap_add(struct plugin_stagem
**stm
, struct plugin
*p
)
76 struct plugin_stagem
*list
, *new;
78 new = mk_mem_malloc_z(sizeof(struct plugin_stagem
));
96 void mk_plugin_register_stagemap(struct plugin
*p
)
98 /* Plugin to stages */
99 if (*p
->hooks
& MK_PLUGIN_STAGE_10
) {
100 mk_plugin_register_stagemap_add(&plg_stagemap
->stage_10
, p
);
103 if (*p
->hooks
& MK_PLUGIN_STAGE_20
) {
104 mk_plugin_register_stagemap_add(&plg_stagemap
->stage_20
, p
);
107 if (*p
->hooks
& MK_PLUGIN_STAGE_30
) {
108 mk_plugin_register_stagemap_add(&plg_stagemap
->stage_30
, p
);
111 if (*p
->hooks
& MK_PLUGIN_STAGE_40
) {
112 mk_plugin_register_stagemap_add(&plg_stagemap
->stage_40
, p
);
115 if (*p
->hooks
& MK_PLUGIN_STAGE_50
) {
116 mk_plugin_register_stagemap_add(&plg_stagemap
->stage_50
, p
);
120 struct plugin
*mk_plugin_alloc(void *handler
, char *path
)
124 p
= mk_mem_malloc_z(sizeof(struct plugin
));
125 p
->shortname
= mk_plugin_load_symbol(handler
, "_shortname");
126 p
->name
= mk_plugin_load_symbol(handler
, "_name");
127 p
->version
= mk_plugin_load_symbol(handler
, "_version");
128 p
->path
= mk_string_dup(path
);
129 p
->handler
= handler
;
130 p
->hooks
= (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
,
139 p
->core
.thctx
= (int (*)()) mk_plugin_load_symbol(handler
,
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 p
->net_io
.create_socket
= (int (*)())
181 mk_plugin_load_symbol(handler
, "_mkp_network_io_create_socket");
183 p
->net_io
.bind
= (int (*)())
184 mk_plugin_load_symbol(handler
, "_mkp_network_io_bind");
186 p
->net_io
.server
= (int (*)())
187 mk_plugin_load_symbol(handler
, "_mkp_network_io_server");
190 /* Network IP hooks */
191 p
->net_ip
.addr
= (int (*)())
192 mk_plugin_load_symbol(handler
, "_mkp_network_ip_addr");
194 p
->net_ip
.maxlen
= (int (*)())
195 mk_plugin_load_symbol(handler
, "_mkp_network_ip_maxlen");
198 p
->thread_key
= (pthread_key_t
*) mk_plugin_load_symbol(handler
,
201 /* Event handlers hooks */
202 p
->event_read
= (int (*)())
203 mk_plugin_load_symbol(handler
, "_mkp_event_read");
205 p
->event_write
= (int (*)())
206 mk_plugin_load_symbol(handler
, "_mkp_event_write");
208 p
->event_error
= (int (*)())
209 mk_plugin_load_symbol(handler
, "_mkp_event_error");
211 p
->event_close
= (int (*)())
212 mk_plugin_load_symbol(handler
, "_mkp_event_close");
214 p
->event_timeout
= (int (*)())
215 mk_plugin_load_symbol(handler
, "_mkp_event_timeout");
223 /* Load the plugins and set the library symbols to the
224 * local struct plugin *p node
226 struct plugin
*mk_plugin_register(struct plugin
*p
)
228 if (!p
->name
|| !p
->version
|| !p
->hooks
) {
230 MK_TRACE("Plugin must define name, version and hooks. Check: %s", p
->path
);
236 if (!p
->init
|| !p
->exit
) {
238 MK_TRACE("Plugin must define hooks 'init' and 'exit'");
244 /* NETWORK_IO Plugin */
245 if (*p
->hooks
& MK_PLUGIN_NETWORK_IO
) {
246 /* Validate mandatory calls */
247 if (!p
->net_io
.accept
|| !p
->net_io
.read
|| !p
->net_io
.write
||
248 !p
->net_io
.writev
|| !p
->net_io
.close
|| !p
->net_io
.connect
||
249 !p
->net_io
.send_file
|| !p
->net_io
.create_socket
|| !p
->net_io
.bind
||
250 !p
->net_io
.server
) {
252 MK_TRACE("Networking IO plugin incomplete: %s", p
->path
);
253 MK_TRACE("Mapped Functions\naccept : %p\nread : %p\n\
254 write : %p\nwritev: %p\nclose : %p\nconnect : %p\nsendfile : %p\n\
255 create socket : %p\nbind : %p\nserver : %p",
263 p
->net_io
.create_socket
,
271 /* Restrict to one NETWORK_IO plugin */
273 plg_netiomap
= &p
->net_io
;
277 "\nError: Loading more than one Network IO Plugin: %s",
283 /* NETWORK_IP Plugin */
284 if (*p
->hooks
& MK_PLUGIN_NETWORK_IP
) {
285 /* Validate mandatory calls */
286 if (!p
->net_ip
.addr
|| !p
->net_ip
.maxlen
) {
288 MK_TRACE("Networking IP plugin incomplete: %s", p
->path
);
289 MK_TRACE("Mapped Functions\naddr :%p\nmaxlen :%p",
297 /* Restrict to one NETWORK_IP plugin */
299 plg_netipmap
= &p
->net_ip
;
303 "\nError: Loading more than one Network IP Plugin: %s",
309 /* Add Plugin to the end of the list */
310 if (!config
->plugins
) {
314 struct plugin
*plg
= config
->plugins
;
321 mk_plugin_register_stagemap(p
);
325 void mk_plugin_unregister(struct plugin
*p
)
327 struct plugin
*node
, *prev
;
329 node
= config
->plugins
;
336 config
->plugins
= p
->next
;
342 while (node
->next
!= p
) {
348 prev
->next
= p
->next
;
354 void mk_plugin_free(struct plugin
*p
)
356 mk_mem_free(p
->path
);
361 void mk_plugin_init()
365 char *plugin_confdir
= 0;
369 struct plugin_api
*api
;
370 struct mk_config
*cnf
;
371 struct mk_config_section
*section
;
372 struct mk_config_entry
*entry
;
374 api
= mk_mem_malloc_z(sizeof(struct plugin_api
));
375 plg_stagemap
= mk_mem_malloc_z(sizeof(struct plugin_stagemap
));
379 /* Setup and connections list */
380 api
->config
= config
;
381 api
->sched_list
= &sched_list
;
383 /* API plugins funcions */
386 api
->http_request_end
= (void *) mk_plugin_http_request_end
;
388 /* Memory callbacks */
389 api
->pointer_set
= (void *) mk_pointer_set
;
390 api
->pointer_print
= (void *) mk_pointer_print
;
391 api
->plugin_load_symbol
= (void *) mk_plugin_load_symbol
;
392 api
->mem_alloc
= (void *) mk_mem_malloc
;
393 api
->mem_alloc_z
= (void *) mk_mem_malloc_z
;
394 api
->mem_free
= (void *) mk_mem_free
;
396 /* String Callbacks */
397 api
->str_build
= (void *) mk_string_build
;
398 api
->str_dup
= (void *) mk_string_dup
;
399 api
->str_search
= (void *) mk_string_search
;
400 api
->str_search_n
= (void *) mk_string_search_n
;
401 api
->str_copy_substr
= (void *) mk_string_copy_substr
;
402 api
->str_itop
= (void *) mk_string_itop
;
403 api
->str_split_line
= (void *) mk_string_split_line
;
406 api
->file_to_buffer
= (void *) mk_file_to_buffer
;
407 api
->file_get_info
= (void *) mk_file_get_info
;
410 api
->header_send
= (void *) mk_header_send
;
411 api
->header_set_http_status
= (void *) mk_header_set_http_status
;
414 api
->iov_create
= (void *) mk_iov_create
;
415 api
->iov_free
= (void *) mk_iov_free
;
416 api
->iov_add_entry
= (void *) mk_iov_add_entry
;
417 api
->iov_set_entry
= (void *) mk_iov_set_entry
;
418 api
->iov_send
= (void *) mk_iov_send
;
419 api
->iov_print
= (void *) mk_iov_print
;
421 /* EPoll callbacks */
422 api
->epoll_create
= (void *) mk_epoll_create
;
423 api
->epoll_init
= (void *) mk_epoll_init
;
424 api
->epoll_add
= (void *) mk_epoll_add
;
425 api
->epoll_del
= (void *) mk_epoll_del
;
426 api
->epoll_change_mode
= (void *) mk_epoll_change_mode
;
428 /* Socket callbacks */
429 api
->socket_cork_flag
= (void *) mk_socket_set_cork_flag
;
430 api
->socket_connect
= (void *) mk_socket_connect
;
431 api
->socket_reset
= (void *) mk_socket_reset
;
432 api
->socket_set_tcp_nodelay
= (void *) mk_socket_set_tcp_nodelay
;
433 api
->socket_set_nonblocking
= (void *) mk_socket_set_nonblocking
;
434 api
->socket_create
= (void *) mk_socket_create
;
435 api
->socket_close
= (void *) mk_socket_close
;
436 api
->socket_sendv
= (void *) mk_socket_sendv
;
437 api
->socket_send
= (void *) mk_socket_send
;
438 api
->socket_read
= (void *) mk_socket_read
;
439 api
->socket_send_file
= (void *) mk_socket_send_file
;
441 /* Config Callbacks */
442 api
->config_create
= (void *) mk_config_create
;
443 api
->config_free
= (void *) mk_config_free
;
444 api
->config_section_get
= (void *) mk_config_section_get
;
445 api
->config_section_getval
= (void *) mk_config_section_getval
;
447 /* Scheduler and Event callbacks */
448 api
->sched_get_connection
= (void *) mk_sched_get_connection
;
449 api
->event_add
= (void *) mk_plugin_event_add
;
450 api
->event_del
= (void *) mk_plugin_event_del
;
451 api
->event_socket_change_mode
= (void *) mk_plugin_event_socket_change_mode
;
453 /* Worker functions */
454 api
->worker_spawn
= (void *) mk_worker_spawn
;
456 /* Some useful functions =) */
457 api
->sys_get_somaxconn
= (void *) mk_utils_get_somaxconn
;
460 api
->time_unix
= (void *) mk_plugin_time_now_unix
;
461 api
->time_human
= (void *) mk_plugin_time_now_human
;
464 api
->trace
= (void *) mk_utils_trace
;
467 /* Read configuration file */
468 path
= mk_mem_malloc_z(1024);
469 snprintf(path
, 1024, "%s/%s", config
->serverconf
, MK_PLUGIN_LOAD
);
470 cnf
= mk_config_create(path
);
473 puts("Error: Plugins configuration file could not be readed");
477 /* Read section 'PLUGINS' */
478 section
= mk_config_section_get(cnf
, "PLUGINS");
480 /* Read key entries */
481 entry
= section
->entry
;
483 if (strcasecmp(entry
->key
, "Load") == 0) {
484 handle
= mk_plugin_load(entry
->val
);
486 p
= mk_plugin_alloc(handle
, entry
->val
);
488 fprintf(stderr
, "Plugin error: %s\n", entry
->val
);
492 /* Build plugin configuration path */
493 mk_string_build(&plugin_confdir
,
496 config
->serverconf
, p
->shortname
);
499 MK_TRACE("Load Plugin '%s@%s'", p
->shortname
, p
->path
);
502 ret
= p
->init(&api
, plugin_confdir
);
504 /* Free plugin, do not register */
506 MK_TRACE("Unregister plugin '%s'", p
->shortname
);
513 /* If everything worked, register plugin */
514 mk_plugin_register(p
);
520 fprintf(stderr
, "\nError: no Network plugin loaded >:|\n\n");
524 api
->plugins
= config
->plugins
;
525 /* Look for plugins thread key data */
526 mk_plugin_preworker_calls();
530 int mk_plugin_stage_run(mk_plugin_hook_t hook
,
532 struct sched_connection
*conx
,
533 struct client_request
*cr
, struct request
*sr
)
536 struct plugin_stagem
*stm
;
538 /* Connection just accept(ed) not assigned to worker thread */
539 if (hook
& MK_PLUGIN_STAGE_10
) {
540 stm
= plg_stagemap
->stage_10
;
543 MK_TRACE("[%s] STAGE 10", stm
->p
->shortname
);
545 ret
= stm
->p
->stage
.s10(socket
, conx
);
547 case MK_PLUGIN_RET_CLOSE_CONX
:
549 MK_TRACE("return MK_PLUGIN_RET_CLOSE_CONX");
551 return MK_PLUGIN_RET_CLOSE_CONX
;
558 /* The HTTP Request stream has been just received */
559 if (hook
& MK_PLUGIN_STAGE_20
) {
560 stm
= plg_stagemap
->stage_20
;
563 MK_TRACE("[%s] STAGE 20", stm
->p
->shortname
);
565 ret
= stm
->p
->stage
.s20(cr
, sr
);
567 case MK_PLUGIN_RET_CLOSE_CONX
:
569 MK_TRACE("return MK_PLUGIN_RET_CLOSE_CONX");
571 return MK_PLUGIN_RET_CLOSE_CONX
;
578 /* The plugin acts like an Object handler, it will take care of the
579 * request, it decides what to do with the request
581 if (hook
& MK_PLUGIN_STAGE_30
) {
582 /* The request just arrived and is required to check who can
584 if (!sr
->handled_by
){
585 stm
= plg_stagemap
->stage_30
;
589 MK_TRACE("[%s] STAGE 30", stm
->p
->shortname
);
591 ret
= stm
->p
->stage
.s30(stm
->p
, cr
, sr
);
594 case MK_PLUGIN_RET_NOT_ME
:
596 case MK_PLUGIN_RET_CONTINUE
:
597 return MK_PLUGIN_RET_CONTINUE
;
598 case MK_PLUGIN_RET_END
:
599 return MK_PLUGIN_RET_END
;
607 /* The request has ended, the content has been served */
608 if (hook
& MK_PLUGIN_STAGE_40
) {
609 stm
= plg_stagemap
->stage_40
;
612 MK_TRACE("[%s] STAGE 40", stm
->p
->shortname
);
614 ret
= stm
->p
->stage
.s40(cr
, sr
);
619 /* The request has ended, the content has been served */
620 if (hook
& MK_PLUGIN_STAGE_50
) {
621 stm
= plg_stagemap
->stage_50
;
624 MK_TRACE("[%s] STAGE 50", stm
->p
->shortname
);
626 ret
= stm
->p
->stage
.s50(socket
);
628 case MK_PLUGIN_RET_NOT_ME
:
630 case MK_PLUGIN_RET_CONTINUE
:
631 return MK_PLUGIN_RET_CONTINUE
;
640 void mk_plugin_request_handler_add(struct request
*sr
, struct plugin
*p
)
642 if (!sr
->handled_by
) {
648 void mk_plugin_request_handler_del(struct request
*sr
, struct plugin
*p
)
650 if (!sr
->handled_by
) {
654 mk_mem_free(sr
->handled_by
);
657 /* This function is called by every created worker
658 * for plugins which need to set some data under a thread
661 void mk_plugin_core_process()
670 p
->core
.prctx(config
);
677 /* This function is called by every created worker
678 * for plugins which need to set some data under a thread
681 void mk_plugin_core_thread()
688 /* Init plugin thread context */
697 /* This function is called by Monkey *outside* of the
698 * thread context for plugins, so here's the right
699 * place to set pthread keys or similar
701 void mk_plugin_preworker_calls()
709 /* Init pthread keys */
712 MK_TRACE("[%s] Set thread key", p
->shortname
);
714 ret
= pthread_key_create(p
->thread_key
, NULL
);
716 printf("\nPlugin Error: could not create key for %s",
726 int mk_plugin_event_del(int socket
)
728 struct plugin_event
*list
, *aux
, *prev
;
731 MK_TRACE("[FD %i] Plugin delete event", socket
);
738 list
= mk_plugin_event_get_list();
742 if (aux
->socket
== socket
) {
748 while (prev
->next
!= aux
) {
752 prev
->next
= aux
->next
;
755 mk_plugin_event_set_list(list
);
762 MK_TRACE("[FD %i] not found :/");
769 int mk_plugin_event_add(int socket
, int mode
,
770 struct plugin
*handler
,
771 struct client_request
*cr
,
774 struct sched_list_node
*sched
;
775 struct plugin_event
*list
;
776 struct plugin_event
*aux
;
777 struct plugin_event
*event
;
779 sched
= mk_sched_get_thread_conf();
781 if (!sched
|| !handler
|| !cr
|| !sr
) {
785 /* Event node (this list exist at thread level */
786 event
= mk_mem_malloc(sizeof(struct plugin_event
));
787 event
->socket
= socket
;
788 event
->handler
= handler
;
793 /* Get thread event list */
794 list
= mk_plugin_event_get_list();
796 mk_plugin_event_set_list(event
);
805 mk_plugin_event_set_list(list
);
808 /* The thread event info has been registered, now we need
809 to register the socket involved to the thread epoll array */
810 mk_epoll_add(sched
->epoll_fd
, event
->socket
,
811 mode
, MK_EPOLL_BEHAVIOR_DEFAULT
);
815 int mk_plugin_http_request_end(int socket
)
819 ret
= mk_http_request_end(socket
);
822 MK_TRACE("PLUGIN HTTP REQUEST END [FD=%i] = ret %i", socket
, ret
);
826 return mk_conn_close(socket
);
832 int mk_plugin_event_socket_change_mode(int socket
, int mode
)
834 struct sched_list_node
*sched
;
836 sched
= mk_sched_get_thread_conf();
842 return mk_epoll_change_mode(sched
->epoll_fd
, socket
, mode
);
845 struct plugin_event
*mk_plugin_event_get(int socket
)
847 struct plugin_event
*event
;
849 event
= mk_plugin_event_get_list();
852 if (event
->socket
== socket
) {
862 int mk_plugin_event_set_list(struct plugin_event
*event
)
864 return pthread_setspecific(mk_plugin_event_k
, event
);
867 struct plugin_event
*mk_plugin_event_get_list()
869 return pthread_getspecific(mk_plugin_event_k
);
873 /* Plugin epoll event handlers
874 * ---------------------------
875 * this functions are called by connection.c functions as mk_conn_read(),
876 * mk_conn_write(),mk_conn_error(), mk_conn_close() and mk_conn_timeout().
880 * MK_PLUGIN_RET_EVENT_NOT_ME: There's no plugin hook associated
883 int mk_plugin_event_read(int socket
)
885 struct plugin_event
*event
;
888 MK_TRACE("[FD %i] Plugin event read", socket
);
891 event
= mk_plugin_event_get(socket
);
894 MK_TRACE(" not handled by plugin");
896 return MK_PLUGIN_RET_EVENT_NOT_ME
;
899 if (event
->handler
->event_read
) {
901 MK_TRACE(" handled by plugin");
903 return event
->handler
->event_read(socket
);
906 return MK_PLUGIN_RET_CONTINUE
;
909 int mk_plugin_event_write(int socket
)
911 struct plugin_event
*event
;
914 MK_TRACE("[FD %i] Plugin event write", socket
);
917 event
= mk_plugin_event_get(socket
);
919 return MK_PLUGIN_RET_EVENT_NOT_ME
;
922 if (event
->handler
->event_write
) {
923 return event
->handler
->event_write(socket
);
926 return MK_PLUGIN_RET_CONTINUE
;
929 int mk_plugin_event_error(int socket
)
931 struct plugin_event
*event
;
934 MK_TRACE("[FD %i] Plugin event error", socket
);
937 event
= mk_plugin_event_get(socket
);
939 return MK_PLUGIN_RET_EVENT_NOT_ME
;
942 if (event
->handler
->event_error
) {
943 return event
->handler
->event_error(socket
);
946 return MK_PLUGIN_RET_CONTINUE
;
949 int mk_plugin_event_close(int socket
)
951 struct plugin_event
*event
;
954 MK_TRACE("[FD %i] Plugin event close", socket
);
957 event
= mk_plugin_event_get(socket
);
959 return MK_PLUGIN_RET_EVENT_NOT_ME
;
962 if (event
->handler
->event_close
) {
963 return event
->handler
->event_close(socket
);
969 int mk_plugin_event_timeout(int socket
)
971 struct plugin_event
*event
;
974 MK_TRACE("[FD %i] Plugin event timeout", socket
);
977 event
= mk_plugin_event_get(socket
);
979 return MK_PLUGIN_RET_EVENT_NOT_ME
;
982 if (event
->handler
->event_timeout
) {
983 return event
->handler
->event_timeout(socket
);
989 int mk_plugin_time_now_unix()
991 return log_current_utime
;
994 mk_pointer
*mk_plugin_time_now_human()
996 return &log_current_time
;