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
) {
188 mk_plugin_register_stages(p
);
192 void mk_plugin_init()
197 struct plugin_api
*api
;
198 struct plugin_list
*plist
;
199 struct mk_config
*cnf
;
201 api
= mk_mem_malloc_z(sizeof(struct plugin_api
));
203 /* Setup and connections list */
204 api
->config
= config
;
205 api
->sched_list
= &sched_list
;
207 /* API plugins funcions */
208 api
->mem_alloc
= (void *) mk_mem_malloc
;
209 api
->mem_alloc_z
= (void *) mk_mem_malloc_z
;
210 api
->mem_free
= (void *) mk_mem_free
;
211 api
->str_build
= (void *) m_build_buffer
;
212 api
->str_dup
= (void *) mk_string_dup
;
213 api
->str_search
= (void *) mk_string_search
;
214 api
->str_search_n
= (void *) mk_string_search_n
;
215 api
->str_copy_substr
= (void *) mk_string_copy_substr
;
216 api
->str_split_line
= (void *) mk_string_split_line
;
217 api
->file_to_buffer
= (void *) mk_file_to_buffer
;
218 api
->file_get_info
= (void *) mk_file_get_info
;
219 api
->header_send
= (void *) mk_header_send
;
220 api
->iov_create
= (void *) mk_iov_create
;
221 api
->iov_free
= (void *) mk_iov_free
;
222 api
->iov_add_entry
= (void *) mk_iov_add_entry
;
223 api
->iov_set_entry
= (void *) mk_iov_set_entry
;
224 api
->iov_send
= (void *) mk_iov_send
;
225 api
->iov_print
= (void *) mk_iov_print
;
226 api
->pointer_set
= (void *) mk_pointer_set
;
227 api
->pointer_print
= (void *) mk_pointer_print
;
228 api
->plugin_load_symbol
= (void *) mk_plugin_load_symbol
;
229 api
->socket_cork_flag
= (void *) mk_socket_set_cork_flag
;
230 api
->socket_connect
= (void *) mk_socket_connect
;
231 api
->socket_set_tcp_nodelay
= (void *) mk_socket_set_tcp_nodelay
;
232 api
->socket_set_nonblocking
= (void *) mk_socket_set_nonblocking
;
233 api
->socket_create
= (void *) mk_socket_create
;
234 api
->config_create
= (void *) mk_config_create
;
235 api
->config_free
= (void *) mk_config_free
;
236 api
->config_getval
= (void *) mk_config_getval
;
237 api
->sched_get_connection
= (void *) mk_sched_get_connection
;
238 api
->event_add
= (void *) mk_plugin_event_add
;
239 api
->event_socket_change_mode
= (void *) mk_plugin_event_socket_change_mode
;
242 api
->trace
= (void *) mk_utils_trace
;
245 path
= mk_mem_malloc_z(1024);
246 snprintf(path
, 1024, "%s/%s", config
->serverconf
, MK_PLUGIN_LOAD
);
248 /* Read configuration file */
249 cnf
= mk_config_create(path
);
252 if (strcasecmp(cnf
->key
, "LoadPlugin") == 0) {
253 handle
= mk_plugin_load(cnf
->val
);
254 p
= mk_plugin_register(handle
, cnf
->val
);
256 fprintf(stderr
, "Plugin error: %s", cnf
->val
);
260 char *plugin_confdir
= 0;
263 m_build_buffer(&plugin_confdir
,
266 config
->serverconf
, p
->shortname
);
268 p
->call_init(&api
, plugin_confdir
);
274 api
->plugins
= plg_list
;
279 int mk_plugin_stage_run(mk_plugin_stage_t stage
,
281 struct sched_connection
*conx
,
282 struct client_request
*cr
, struct request
*sr
)
287 if (stage
& MK_PLUGIN_STAGE_10
) {
288 p
= config
->plugins
->stage_10
;
291 MK_TRACE("[%s] STAGE 10", p
->shortname
);
297 if (stage
& MK_PLUGIN_STAGE_20
) {
298 p
= config
->plugins
->stage_20
;
301 MK_TRACE("[%s] STAGE 20", p
->shortname
);
303 ret
= p
->call_stage_20(socket
, conx
, cr
);
305 case MK_PLUGIN_RET_CLOSE_CONX
:
307 MK_TRACE("return MK_PLUGIN_RET_CLOSE_CONX");
309 return MK_PLUGIN_RET_CLOSE_CONX
;
316 if (stage
& MK_PLUGIN_STAGE_30
) {
317 p
= config
->plugins
->stage_30
;
320 MK_TRACE("[%s] STAGE 30", p
->shortname
);
322 ret
= p
->call_stage_30(cr
, sr
);
324 case MK_PLUGIN_RET_CLOSE_CONX
:
325 return MK_PLUGIN_RET_CLOSE_CONX
;
333 if (stage
& MK_PLUGIN_STAGE_40
) {
334 /* The request just arrived and is required to check who can
336 if (!sr
->handled_by
){
337 p
= config
->plugins
->stage_40
;
341 MK_TRACE("[%s] STAGE 40", p
->shortname
);
343 ret
= p
->call_stage_40(p
, cr
, sr
);
346 case MK_PLUGIN_RET_NOT_ME
:
348 case MK_PLUGIN_RET_CONTINUE
:
349 return MK_PLUGIN_RET_CONTINUE
;
359 void mk_plugin_request_handler_add(struct request
*sr
, struct plugin
*p
)
361 if (!sr
->handled_by
) {
367 void mk_plugin_request_handler_del(struct request
*sr
, struct plugin
*p
)
369 if (!sr
->handled_by
) {
373 mk_mem_free(sr
->handled_by
);
376 /* This function is called by every created worker
377 * for plugins which need to set some data under a thread
380 void mk_plugin_worker_startup()
382 struct plugin_list
*plg
;
388 if (plg
->p
->call_worker_init
) {
389 plg
->p
->call_worker_init();
396 /* This function is called by Monkey *outside* of the
397 * thread context for plugins, so here's the right
398 * place to set pthread keys or similar
400 void mk_plugin_preworker_calls()
403 struct plugin_list
*plg
;
408 /* Init pthread keys */
409 if (plg
->p
->thread_key
) {
410 ret
= pthread_key_create(&plg
->p
->thread_key
, NULL
);
412 printf("\nPlugin Error: could not create key for %s",
422 int mk_plugin_event_add(int socket
, struct plugin
*handler
,
423 struct client_request
*cr
,
426 struct sched_list_node
*sched
;
427 struct plugin_event
*list
;
428 struct plugin_event
*aux
;
429 struct plugin_event
*event
;
431 sched
= mk_sched_get_thread_conf();
433 if (!sched
|| !handler
|| !cr
|| !sr
) {
437 /* Event node (this list exist at thread level */
438 event
= mk_mem_malloc(sizeof(struct plugin_event
));
439 event
->socket
= socket
;
440 event
->handler
= handler
;
445 /* Get thread event list */
446 list
= mk_plugin_event_get_list();
448 mk_plugin_event_set_list(event
);
457 mk_plugin_event_set_list(aux
);
460 /* The thread event info has been registered, now we need
461 to register the socket involved to the thread epoll array */
462 mk_epoll_add_client(sched
->epoll_fd
, event
->socket
,
463 MK_EPOLL_WRITE
, MK_EPOLL_BEHAVIOR_TRIGGERED
);
467 int mk_plugin_event_socket_change_mode(int socket
, int mode
)
469 struct sched_list_node
*sched
;
471 sched
= mk_sched_get_thread_conf();
477 return mk_epoll_socket_change_mode(sched
->epoll_fd
, socket
, mode
);
480 struct plugin_event
*mk_plugin_event_get(int socket
)
482 struct plugin_event
*event
;
484 event
= mk_plugin_event_get_list();
487 if (event
->socket
== socket
) {
497 int mk_plugin_event_set_list(struct plugin_event
*event
)
499 return pthread_setspecific(mk_plugin_event_k
, (void *) event
);
502 struct plugin_event
*mk_plugin_event_get_list()
504 return (struct plugin_event
*) pthread_getspecific(mk_plugin_event_k
);
508 /* Plugin epoll event handlers
509 * ---------------------------
510 * this functions are called by connection.c functions as mk_conn_read(),
511 * mk_conn_write(),mk_conn_error(), mk_conn_close() and mk_conn_timeout
515 * MK_PLUGIN_RET_EVENT_NOT_ME: There's no plugin hook associated
518 int mk_plugin_event_read(int socket
)
520 struct plugin_event
*event
;
523 MK_TRACE("Plugin, event read");
526 event
= mk_plugin_event_get(socket
);
528 return MK_PLUGIN_RET_EVENT_NOT_ME
;
531 if (event
->handler
->call_stage_40_event_read
) {
532 event
->handler
->call_stage_40_event_read(event
->cr
, event
->sr
);
535 return MK_PLUGIN_RET_CONTINUE
;
538 int mk_plugin_event_write(int socket
)
540 struct plugin_event
*event
;
543 MK_TRACE("Plugin, event write fd %i", socket
);
546 event
= mk_plugin_event_get(socket
);
548 return MK_PLUGIN_RET_EVENT_NOT_ME
;
551 if (event
->handler
->call_stage_40_event_write
) {
552 event
->handler
->call_stage_40_event_write(event
->cr
, event
->sr
);
555 return MK_PLUGIN_RET_CONTINUE
;
558 int mk_plugin_event_error(int socket
)
561 MK_TRACE("Plugin, event error fd %i", socket
);
567 int mk_plugin_event_close(int socket
)
571 MK_TRACE("Plugin, event close fd %i", socket
);
577 int mk_plugin_event_timeout(int socket
)
581 MK_TRACE("Plugin, event timeout fd %i", socket
);