1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 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.
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_add_to_stage(struct plugin
**st
, struct plugin
*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
));
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
)
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
;
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
,
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");
183 if (!p
->name
|| !p
->version
|| !p
->stages
) {
185 MK_TRACE("Bad plugin definition: %s", path
);
191 mk_plugin_register_stages(p
);
195 void mk_plugin_init()
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
;
245 api
->trace
= (void *) mk_utils_trace
;
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
);
255 if (strcasecmp(cnf
->key
, "LoadPlugin") == 0) {
256 handle
= mk_plugin_load(cnf
->val
);
257 p
= mk_plugin_register(handle
, cnf
->val
);
259 fprintf(stderr
, "Plugin error: %s", cnf
->val
);
263 char *plugin_confdir
= 0;
266 m_build_buffer(&plugin_confdir
,
269 config
->serverconf
, p
->shortname
);
271 p
->call_init(&api
, plugin_confdir
);
277 api
->plugins
= plg_list
;
282 int mk_plugin_stage_run(mk_plugin_stage_t stage
,
284 struct sched_connection
*conx
,
285 struct client_request
*cr
, struct request
*sr
)
290 if (stage
& MK_PLUGIN_STAGE_10
) {
291 p
= config
->plugins
->stage_10
;
294 MK_TRACE("[%s] STAGE 10", p
->shortname
);
301 if (stage
& MK_PLUGIN_STAGE_20
) {
302 p
= config
->plugins
->stage_20
;
305 MK_TRACE("[%s] STAGE 20", p
->shortname
);
307 ret
= p
->call_stage_20(socket
, conx
, cr
);
309 case MK_PLUGIN_RET_CLOSE_CONX
:
311 MK_TRACE("return MK_PLUGIN_RET_CLOSE_CONX");
313 return MK_PLUGIN_RET_CLOSE_CONX
;
320 if (stage
& MK_PLUGIN_STAGE_30
) {
321 p
= config
->plugins
->stage_30
;
324 MK_TRACE("[%s] STAGE 30", p
->shortname
);
326 ret
= p
->call_stage_30(cr
, sr
);
328 case MK_PLUGIN_RET_CLOSE_CONX
:
329 return MK_PLUGIN_RET_CLOSE_CONX
;
337 if (stage
& MK_PLUGIN_STAGE_40
) {
338 /* The request just arrived and is required to check who can
340 if (!sr
->handled_by
){
341 p
= config
->plugins
->stage_40
;
345 MK_TRACE("[%s] STAGE 40", p
->shortname
);
347 ret
= p
->call_stage_40(p
, cr
, sr
);
350 case MK_PLUGIN_RET_NOT_ME
:
352 case MK_PLUGIN_RET_CONTINUE
:
353 return MK_PLUGIN_RET_CONTINUE
;
363 void mk_plugin_request_handler_add(struct request
*sr
, struct plugin
*p
)
365 if (!sr
->handled_by
) {
371 void mk_plugin_request_handler_del(struct request
*sr
, struct plugin
*p
)
373 if (!sr
->handled_by
) {
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
384 void mk_plugin_worker_startup()
386 struct plugin_list
*plg
;
392 if (plg
->p
->call_worker_init
) {
393 plg
->p
->call_worker_init();
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()
407 struct plugin_list
*plg
;
412 /* Init pthread keys */
413 if (plg
->p
->thread_key
) {
414 ret
= pthread_key_create(&plg
->p
->thread_key
, NULL
);
416 printf("\nPlugin Error: could not create key for %s",
426 int mk_plugin_event_add(int socket
, struct plugin
*handler
,
427 struct client_request
*cr
,
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
) {
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
;
449 /* Get thread event list */
450 list
= mk_plugin_event_get_list();
452 mk_plugin_event_set_list(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
);
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();
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();
491 if (event
->socket
== socket
) {
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
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
;
527 MK_TRACE("Plugin, event read FD %i", socket
);
530 event
= mk_plugin_event_get(socket
);
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
;
547 MK_TRACE("Plugin, event write FD %i", socket
);
550 event
= mk_plugin_event_get(socket
);
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
)
565 MK_TRACE("Plugin, event error FD %i", socket
);
571 int mk_plugin_event_close(int socket
)
575 MK_TRACE("Plugin, event close FD %i", socket
);
581 int mk_plugin_event_timeout(int socket
)
585 MK_TRACE("Plugin, event timeout FD %i", socket
);