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"
47 void *mk_plugin_load(char *path
)
51 handle
= dlopen(path
, RTLD_LAZY
);
53 fprintf(stderr
, "Error during dlopen(): %s\n", dlerror());
59 void *mk_plugin_load_symbol(void *handler
, const char *symbol
)
65 s
= dlsym(handler
, symbol
);
66 if ((err
= dlerror()) != NULL
) {
73 void mk_plugin_register_stagemap_add(struct plugin_stagem
**stm
, struct plugin
*p
)
75 struct plugin_stagem
*list
, *new;
77 new = mk_mem_malloc_z(sizeof(struct plugin_stagem
));
95 void mk_plugin_register_stagemap(struct plugin
*p
)
97 /* Plugin to stages */
98 if (*p
->hooks
& MK_PLUGIN_STAGE_10
) {
99 mk_plugin_register_stagemap_add(&plg_stagemap
->stage_10
, p
);
102 if (*p
->hooks
& MK_PLUGIN_STAGE_20
) {
103 mk_plugin_register_stagemap_add(&plg_stagemap
->stage_20
, p
);
106 if (*p
->hooks
& MK_PLUGIN_STAGE_30
) {
107 mk_plugin_register_stagemap_add(&plg_stagemap
->stage_30
, p
);
110 if (*p
->hooks
& MK_PLUGIN_STAGE_40
) {
111 mk_plugin_register_stagemap_add(&plg_stagemap
->stage_40
, p
);
114 if (*p
->hooks
& MK_PLUGIN_STAGE_50
) {
115 mk_plugin_register_stagemap_add(&plg_stagemap
->stage_50
, p
);
119 struct plugin
*mk_plugin_alloc(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
;
129 p
->hooks
= (mk_plugin_hook_t
*) mk_plugin_load_symbol(handler
, "_hooks");
131 /* Mandatory functions */
132 p
->init
= (int (*)()) mk_plugin_load_symbol(handler
, "_mkp_init");
133 p
->exit
= (int (*)()) mk_plugin_load_symbol(handler
, "_mkp_exit");
136 p
->core
.prctx
= (int (*)()) mk_plugin_load_symbol(handler
,
138 p
->core
.thctx
= (int (*)()) mk_plugin_load_symbol(handler
,
142 p
->stage
.s10
= (int (*)())
143 mk_plugin_load_symbol(handler
, "_mkp_stage_10");
145 p
->stage
.s20
= (int (*)())
146 mk_plugin_load_symbol(handler
, "_mkp_stage_20");
148 p
->stage
.s30
= (int (*)())
149 mk_plugin_load_symbol(handler
, "_mkp_stage_30");
151 p
->stage
.s40
= (int (*)())
152 mk_plugin_load_symbol(handler
, "_mkp_stage_40");
154 p
->stage
.s50
= (int (*)())
155 mk_plugin_load_symbol(handler
, "_mkp_stage_50");
157 /* Network I/O hooks */
158 p
->net_io
.accept
= (int (*)())
159 mk_plugin_load_symbol(handler
, "_mkp_network_io_accept");
161 p
->net_io
.read
= (int (*)())
162 mk_plugin_load_symbol(handler
, "_mkp_network_io_read");
164 p
->net_io
.write
= (int (*)())
165 mk_plugin_load_symbol(handler
, "_mkp_network_io_write");
167 p
->net_io
.writev
= (int (*)())
168 mk_plugin_load_symbol(handler
, "_mkp_network_io_writev");
170 p
->net_io
.close
= (int (*)())
171 mk_plugin_load_symbol(handler
, "_mkp_network_io_close");
173 p
->net_io
.connect
= (int (*)())
174 mk_plugin_load_symbol(handler
, "_mkp_network_io_connect");
176 p
->net_io
.send_file
= (int (*)())
177 mk_plugin_load_symbol(handler
, "_mkp_network_io_send_file");
179 p
->net_io
.create_socket
= (int (*)())
180 mk_plugin_load_symbol(handler
, "_mkp_network_io_create_socket");
182 p
->net_io
.bind
= (int (*)())
183 mk_plugin_load_symbol(handler
, "_mkp_network_io_bind");
185 p
->net_io
.server
= (int (*)())
186 mk_plugin_load_symbol(handler
, "_mkp_network_io_server");
189 /* Network IP hooks */
190 p
->net_ip
.addr
= (int (*)())
191 mk_plugin_load_symbol(handler
, "_mkp_network_ip_addr");
193 p
->net_ip
.maxlen
= (int (*)())
194 mk_plugin_load_symbol(handler
, "_mkp_network_ip_maxlen");
197 p
->thread_key
= (pthread_key_t
) mk_plugin_load_symbol(handler
,
200 /* Event handlers hooks */
201 p
->event_read
= (int (*)())
202 mk_plugin_load_symbol(handler
, "_mkp_event_read");
204 p
->event_write
= (int (*)())
205 mk_plugin_load_symbol(handler
, "_mkp_event_write");
207 p
->event_error
= (int (*)())
208 mk_plugin_load_symbol(handler
, "_mkp_event_error");
210 p
->event_close
= (int (*)())
211 mk_plugin_load_symbol(handler
, "_mkp_event_close");
213 p
->event_timeout
= (int (*)())
214 mk_plugin_load_symbol(handler
, "_mkp_event_timeout");
222 /* Load the plugins and set the library symbols to the
223 * local struct plugin *p node
225 struct plugin
*mk_plugin_register(struct plugin
*p
)
227 if (!p
->name
|| !p
->version
|| !p
->hooks
) {
229 MK_TRACE("Plugin must define name, version and hooks. Check: %s", p
->path
);
235 if (!p
->init
|| !p
->exit
) {
237 MK_TRACE("Plugin must define hooks 'init' and 'exit'");
243 /* NETWORK_IO Plugin */
244 if (*p
->hooks
& MK_PLUGIN_NETWORK_IO
) {
245 /* Validate mandatory calls */
246 if (!p
->net_io
.accept
|| !p
->net_io
.read
|| !p
->net_io
.write
||
247 !p
->net_io
.writev
|| !p
->net_io
.close
|| !p
->net_io
.connect
||
248 !p
->net_io
.send_file
|| !p
->net_io
.create_socket
|| !p
->net_io
.bind
||
249 !p
->net_io
.server
) {
251 MK_TRACE("Networking IO plugin incomplete: %s", p
->path
);
252 MK_TRACE("Mapped Functions\naccept : %p\nread : %p\n\
253 write : %p\nwritev: %p\nclose : %p\nconnect : %p\nsendfile : %p\n\
254 create socket : %p\nbind : %p\nserver : %p",
262 p
->net_io
.create_socket
,
270 /* Restrict to one NETWORK_IO plugin */
272 plg_netiomap
= &p
->net_io
;
276 "\nError: Loading more than one Network IO Plugin: %s",
282 /* NETWORK_IP Plugin */
283 if (*p
->hooks
& MK_PLUGIN_NETWORK_IP
) {
284 /* Validate mandatory calls */
285 if (!p
->net_ip
.addr
|| !p
->net_ip
.maxlen
) {
287 MK_TRACE("Networking IP plugin incomplete: %s", p
->path
);
288 MK_TRACE("Mapped Functions\naddr :%p\nmaxlen :%p",
296 /* Restrict to one NETWORK_IP plugin */
298 plg_netipmap
= &p
->net_ip
;
302 "\nError: Loading more than one Network IP Plugin: %s",
308 /* Add Plugin to the end of the list */
309 if (!config
->plugins
) {
313 struct plugin
*plg
= config
->plugins
;
320 mk_plugin_register_stagemap(p
);
324 void mk_plugin_unregister(struct plugin
*p
)
326 struct plugin
*node
, *prev
;
328 node
= config
->plugins
;
335 config
->plugins
= p
->next
;
341 while (node
->next
!= p
) {
347 prev
->next
= p
->next
;
353 void mk_plugin_free(struct plugin
*p
)
355 mk_mem_free(p
->path
);
360 void mk_plugin_init()
364 char *plugin_confdir
= 0;
368 struct plugin_api
*api
;
369 struct mk_config
*cnf
;
370 struct mk_config_section
*section
;
371 struct mk_config_entry
*entry
;
373 api
= mk_mem_malloc_z(sizeof(struct plugin_api
));
374 plg_stagemap
= mk_mem_malloc_z(sizeof(struct plugin_stagemap
));
378 /* Setup and connections list */
379 api
->config
= config
;
380 api
->sched_list
= &sched_list
;
382 /* API plugins funcions */
385 api
->http_request_end
= (void *) mk_plugin_http_request_end
;
387 /* Memory callbacks */
388 api
->pointer_set
= (void *) mk_pointer_set
;
389 api
->pointer_print
= (void *) mk_pointer_print
;
390 api
->plugin_load_symbol
= (void *) mk_plugin_load_symbol
;
391 api
->mem_alloc
= (void *) mk_mem_malloc
;
392 api
->mem_alloc_z
= (void *) mk_mem_malloc_z
;
393 api
->mem_free
= (void *) mk_mem_free
;
395 /* String Callbacks */
396 api
->str_build
= (void *) mk_string_build
;
397 api
->str_dup
= (void *) mk_string_dup
;
398 api
->str_search
= (void *) mk_string_search
;
399 api
->str_search_n
= (void *) mk_string_search_n
;
400 api
->str_copy_substr
= (void *) mk_string_copy_substr
;
401 api
->str_split_line
= (void *) mk_string_split_line
;
404 api
->file_to_buffer
= (void *) mk_file_to_buffer
;
405 api
->file_get_info
= (void *) mk_file_get_info
;
408 api
->header_send
= (void *) mk_header_send
;
411 api
->iov_create
= (void *) mk_iov_create
;
412 api
->iov_free
= (void *) mk_iov_free
;
413 api
->iov_add_entry
= (void *) mk_iov_add_entry
;
414 api
->iov_set_entry
= (void *) mk_iov_set_entry
;
415 api
->iov_send
= (void *) mk_iov_send
;
416 api
->iov_print
= (void *) mk_iov_print
;
418 /* EPoll callbacks */
419 api
->epoll_create
= (void *) mk_epoll_create
;
420 api
->epoll_init
= (void *) mk_epoll_init
;
421 api
->epoll_add
= (void *) mk_epoll_add
;
422 api
->epoll_del
= (void *) mk_epoll_del
;
423 api
->epoll_change_mode
= (void *) mk_epoll_change_mode
;
425 /* Socket callbacks */
426 api
->socket_cork_flag
= (void *) mk_socket_set_cork_flag
;
427 api
->socket_connect
= (void *) mk_socket_connect
;
428 api
->socket_reset
= (void *) mk_socket_reset
;
429 api
->socket_set_tcp_nodelay
= (void *) mk_socket_set_tcp_nodelay
;
430 api
->socket_set_nonblocking
= (void *) mk_socket_set_nonblocking
;
431 api
->socket_create
= (void *) mk_socket_create
;
432 api
->socket_close
= (void *) mk_socket_close
;
433 api
->socket_sendv
= (void *) mk_socket_sendv
;
434 api
->socket_send
= (void *) mk_socket_send
;
435 api
->socket_read
= (void *) mk_socket_read
;
436 api
->socket_send_file
= (void *) mk_socket_send_file
;
438 /* Config Callbacks */
439 api
->config_create
= (void *) mk_config_create
;
440 api
->config_free
= (void *) mk_config_free
;
441 api
->config_section_get
= (void *) mk_config_section_get
;
442 api
->config_section_getval
= (void *) mk_config_section_getval
;
444 /* Scheduler and Event callbacks */
445 api
->sched_get_connection
= (void *) mk_sched_get_connection
;
446 api
->event_add
= (void *) mk_plugin_event_add
;
447 api
->event_socket_change_mode
= (void *) mk_plugin_event_socket_change_mode
;
449 /* Worker functions */
450 api
->worker_spawn
= (void *) mk_worker_spawn
;
452 /* Some useful functions =) */
453 api
->sys_get_somaxconn
= (void *) mk_utils_get_somaxconn
;
455 api
->trace
= (void *) mk_utils_trace
;
458 /* Read configuration file */
459 path
= mk_mem_malloc_z(1024);
460 snprintf(path
, 1024, "%s/%s", config
->serverconf
, MK_PLUGIN_LOAD
);
461 cnf
= mk_config_create(path
);
464 puts("Error: Plugins configuration file could not be readed");
468 /* Read section 'PLUGINS' */
469 section
= mk_config_section_get(cnf
, "PLUGINS");
471 /* Read key entries */
472 entry
= section
->entry
;
474 if (strcasecmp(entry
->key
, "Load") == 0) {
475 handle
= mk_plugin_load(entry
->val
);
477 p
= mk_plugin_alloc(handle
, entry
->val
);
479 fprintf(stderr
, "Plugin error: %s\n", entry
->val
);
483 /* Build plugin configuration path */
484 mk_string_build(&plugin_confdir
,
487 config
->serverconf
, p
->shortname
);
490 MK_TRACE("Load Plugin '%s@%s'", p
->shortname
, p
->path
);
493 ret
= p
->init(&api
, plugin_confdir
);
495 /* Free plugin, do not register */
497 MK_TRACE("Unregister plugin '%s'", p
->shortname
);
504 /* If everything worked, register plugin */
505 mk_plugin_register(p
);
511 fprintf(stderr
, "\nError: no Network plugin loaded >:|\n\n");
515 api
->plugins
= config
->plugins
;
519 int mk_plugin_stage_run(mk_plugin_hook_t hook
,
521 struct sched_connection
*conx
,
522 struct client_request
*cr
, struct request
*sr
)
525 struct plugin_stagem
*stm
;
527 /* Connection just accept(ed) not assigned to worker thread */
528 if (hook
& MK_PLUGIN_STAGE_10
) {
529 stm
= plg_stagemap
->stage_10
;
532 MK_TRACE("[%s] STAGE 10", stm
->p
->shortname
);
534 ret
= stm
->p
->stage
.s10(socket
, conx
);
536 case MK_PLUGIN_RET_CLOSE_CONX
:
538 MK_TRACE("return MK_PLUGIN_RET_CLOSE_CONX");
540 return MK_PLUGIN_RET_CLOSE_CONX
;
547 /* The HTTP Request stream has been just received */
548 if (hook
& MK_PLUGIN_STAGE_20
) {
549 stm
= plg_stagemap
->stage_20
;
552 MK_TRACE("[%s] STAGE 20", stm
->p
->shortname
);
554 ret
= stm
->p
->stage
.s20(cr
, sr
);
556 case MK_PLUGIN_RET_CLOSE_CONX
:
558 MK_TRACE("return MK_PLUGIN_RET_CLOSE_CONX");
560 return MK_PLUGIN_RET_CLOSE_CONX
;
567 /* The plugin acts like an Object handler, it will take care of the
568 * request, it decides what to do with the request
570 if (hook
& MK_PLUGIN_STAGE_30
) {
571 /* The request just arrived and is required to check who can
573 if (!sr
->handled_by
){
574 stm
= plg_stagemap
->stage_30
;
578 MK_TRACE("[%s] STAGE 30", stm
->p
->shortname
);
580 ret
= stm
->p
->stage
.s30(stm
->p
, cr
, sr
);
583 case MK_PLUGIN_RET_NOT_ME
:
585 case MK_PLUGIN_RET_CONTINUE
:
586 return MK_PLUGIN_RET_CONTINUE
;
587 case MK_PLUGIN_RET_END
:
588 return MK_PLUGIN_RET_END
;
596 /* The request has ended, the content has been served */
597 if (hook
& MK_PLUGIN_STAGE_40
) {
598 stm
= plg_stagemap
->stage_40
;
601 MK_TRACE("[%s] STAGE 40", stm
->p
->shortname
);
603 ret
= stm
->p
->stage
.s40(cr
, sr
);
605 case MK_PLUGIN_RET_NOT_ME
:
607 case MK_PLUGIN_RET_CONTINUE
:
608 return MK_PLUGIN_RET_CONTINUE
;
614 /* The request has ended, the content has been served */
615 if (hook
& MK_PLUGIN_STAGE_50
) {
616 stm
= plg_stagemap
->stage_50
;
619 MK_TRACE("[%s] STAGE 50", stm
->p
->shortname
);
621 ret
= stm
->p
->stage
.s50(socket
);
623 case MK_PLUGIN_RET_NOT_ME
:
625 case MK_PLUGIN_RET_CONTINUE
:
626 return MK_PLUGIN_RET_CONTINUE
;
635 void mk_plugin_request_handler_add(struct request
*sr
, struct plugin
*p
)
637 if (!sr
->handled_by
) {
643 void mk_plugin_request_handler_del(struct request
*sr
, struct plugin
*p
)
645 if (!sr
->handled_by
) {
649 mk_mem_free(sr
->handled_by
);
652 /* This function is called by every created worker
653 * for plugins which need to set some data under a thread
656 void mk_plugin_core_process()
665 p
->core
.prctx(config
);
672 /* This function is called by every created worker
673 * for plugins which need to set some data under a thread
676 void mk_plugin_core_thread()
692 /* This function is called by Monkey *outside* of the
693 * thread context for plugins, so here's the right
694 * place to set pthread keys or similar
696 void mk_plugin_preworker_calls()
704 /* Init pthread keys */
706 ret
= pthread_key_create(&p
->thread_key
, NULL
);
708 printf("\nPlugin Error: could not create key for %s",
718 int mk_plugin_event_add(int socket
, int mode
,
719 struct plugin
*handler
,
720 struct client_request
*cr
,
723 struct sched_list_node
*sched
;
724 struct plugin_event
*list
;
725 struct plugin_event
*aux
;
726 struct plugin_event
*event
;
728 sched
= mk_sched_get_thread_conf();
730 if (!sched
|| !handler
|| !cr
|| !sr
) {
734 /* Event node (this list exist at thread level */
735 event
= mk_mem_malloc(sizeof(struct plugin_event
));
736 event
->socket
= socket
;
737 event
->handler
= handler
;
742 /* Get thread event list */
743 list
= mk_plugin_event_get_list();
745 mk_plugin_event_set_list(event
);
754 mk_plugin_event_set_list(aux
);
757 /* The thread event info has been registered, now we need
758 to register the socket involved to the thread epoll array */
759 mk_epoll_add(sched
->epoll_fd
, event
->socket
,
760 mode
, MK_EPOLL_BEHAVIOR_DEFAULT
);
764 int mk_plugin_http_request_end(int socket
)
768 ret
= mk_http_request_end(socket
);
770 return mk_conn_close(socket
);
776 int mk_plugin_event_socket_change_mode(int socket
, int mode
)
778 struct sched_list_node
*sched
;
780 sched
= mk_sched_get_thread_conf();
786 return mk_epoll_change_mode(sched
->epoll_fd
, socket
, mode
);
789 struct plugin_event
*mk_plugin_event_get(int socket
)
791 struct plugin_event
*event
;
793 event
= mk_plugin_event_get_list();
796 if (event
->socket
== socket
) {
806 int mk_plugin_event_set_list(struct plugin_event
*event
)
808 return pthread_setspecific(mk_plugin_event_k
, (void *) event
);
811 struct plugin_event
*mk_plugin_event_get_list()
813 return (struct plugin_event
*) pthread_getspecific(mk_plugin_event_k
);
817 /* Plugin epoll event handlers
818 * ---------------------------
819 * this functions are called by connection.c functions as mk_conn_read(),
820 * mk_conn_write(),mk_conn_error(), mk_conn_close() and mk_conn_timeout
824 * MK_PLUGIN_RET_EVENT_NOT_ME: There's no plugin hook associated
827 int mk_plugin_event_read(int socket
)
829 struct plugin_event
*event
;
832 MK_TRACE("Plugin, event read FD %i", socket
);
835 event
= mk_plugin_event_get(socket
);
837 return MK_PLUGIN_RET_EVENT_NOT_ME
;
840 if (event
->handler
->event_read
) {
841 return event
->handler
->event_read(socket
);
844 return MK_PLUGIN_RET_CONTINUE
;
847 int mk_plugin_event_write(int socket
)
849 struct plugin_event
*event
;
852 MK_TRACE("Plugin, event write FD %i", socket
);
855 event
= mk_plugin_event_get(socket
);
857 return MK_PLUGIN_RET_EVENT_NOT_ME
;
860 if (event
->handler
->event_write
) {
861 return event
->handler
->event_write(socket
);
864 return MK_PLUGIN_RET_CONTINUE
;
867 int mk_plugin_event_error(int socket
)
869 struct plugin_event
*event
;
872 MK_TRACE("Plugin, event error FD %i", socket
);
875 event
= mk_plugin_event_get(socket
);
877 return MK_PLUGIN_RET_EVENT_NOT_ME
;
880 if (event
->handler
->event_error
) {
881 return event
->handler
->event_error(socket
);
884 return MK_PLUGIN_RET_CONTINUE
;
887 int mk_plugin_event_close(int socket
)
889 struct plugin_event
*event
;
892 MK_TRACE("Plugin, event close FD %i", socket
);
895 event
= mk_plugin_event_get(socket
);
897 return MK_PLUGIN_RET_EVENT_NOT_ME
;
900 if (event
->handler
->event_close
) {
901 return event
->handler
->event_close(socket
);
907 int mk_plugin_event_timeout(int socket
)
909 struct plugin_event
*event
;
912 MK_TRACE("Plugin, event timeout FD %i", socket
);
915 event
= mk_plugin_event_get(socket
);
917 return MK_PLUGIN_RET_EVENT_NOT_ME
;
920 if (event
->handler
->event_timeout
) {
921 return event
->handler
->event_timeout(socket
);