From b8e353554635c5804b945f4431d4534e38d58ff7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20B=C3=BChler?= Date: Fri, 8 Aug 2008 18:49:00 +0200 Subject: [PATCH] Enabled options, moved some initializing --- src/connection.c | 47 +++++++++++++++++++------ src/connection.h | 2 +- src/lighttpd.c | 12 ------- src/log.h | 3 ++ src/network.c | 1 + src/options.c | 3 +- src/options.h | 2 +- src/plugin.c | 11 ++++++ src/plugin.h | 11 +++++- src/plugin_core.c | 31 ++++++++++++++++- src/server.c | 87 ++++++++++++++++++++++++++++++----------------- src/server.h | 7 +++- 12 files changed, 155 insertions(+), 62 deletions(-) diff --git a/src/connection.c b/src/connection.c index e21d881..0a5e841 100644 --- a/src/connection.c +++ b/src/connection.c @@ -2,6 +2,7 @@ #include "connection.h" #include "network.h" #include "utils.h" +#include "plugin_core.h" void con_put(server *srv, connection *con); /* server.c */ @@ -118,10 +119,8 @@ static void connection_cb(struct ev_loop *loop, ev_io *w, int revents) { ev_io_rem_events(loop, w, EV_WRITE); break; } - CON_TRACE(srv, con, "cq->len: raw_out=%i, out=%i", (int) con->raw_out->length, (int) con->out->length); } if (con->raw_out->length == 0) { - CON_TRACE(srv, con, "%s", "stop write"); ev_io_rem_events(loop, w, EV_WRITE); dojoblist = TRUE; } @@ -153,6 +152,8 @@ connection* connection_new(server *srv) { action_stack_init(&con->action_stack); + con->options = g_slice_copy(srv->option_count * sizeof(*srv->option_def_values), srv->option_def_values); + request_init(&con->request, con->raw_in); physical_init(&con->physical); response_init(&con->response); @@ -186,6 +187,8 @@ void connection_reset(server *srv, connection *con) { action_stack_reset(srv, &con->action_stack); + memcpy(con->options, srv->option_def_values, srv->option_count * sizeof(*srv->option_def_values)); + request_reset(&con->request); physical_reset(&con->physical); response_reset(&con->response); @@ -207,6 +210,8 @@ void connection_reset_keep_alive(server *srv, connection *con) { action_stack_reset(srv, &con->action_stack); + memcpy(con->options, srv->option_def_values, srv->option_count * sizeof(*srv->option_def_values)); + request_reset(&con->request); physical_reset(&con->physical); response_reset(&con->response); @@ -238,6 +243,8 @@ void connection_free(server *srv, connection *con) { action_stack_clear(srv, &con->action_stack); + g_slice_free1(srv->option_count * sizeof(*srv->option_def_values), con->options); + request_clear(&con->request); physical_clear(&con->physical); response_clear(&con->response); @@ -262,7 +269,9 @@ void connection_state_machine(server *srv, connection *con) { action_enter(con, srv->mainaction); break; case CON_STATE_READ_REQUEST_HEADER: - TRACE(srv, "%s", "reading request header"); + if (CORE_OPTION(CORE_OPTION_DEBUG_REQUEST_HANDLING)) { + TRACE(srv, "%s", "reading request header"); + } switch(http_request_parse(srv, con, &con->request.parser_ctx)) { case HANDLER_FINISHED: case HANDLER_GO_ON: @@ -283,12 +292,16 @@ void connection_state_machine(server *srv, connection *con) { } break; case CON_STATE_VALIDATE_REQUEST_HEADER: - TRACE(srv, "%s", "validating request header"); + if (CORE_OPTION(CORE_OPTION_DEBUG_REQUEST_HANDLING)) { + TRACE(srv, "%s", "validating request header"); + } connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST_HEADER); request_validate_header(srv, con); break; case CON_STATE_HANDLE_REQUEST_HEADER: - TRACE(srv, "%s", "handle request header"); + if (CORE_OPTION(CORE_OPTION_DEBUG_REQUEST_HANDLING)) { + TRACE(srv, "%s", "handle request header"); + } switch (action_execute(srv, con)) { case ACTION_WAIT_FOR_EVENT: done = TRUE; @@ -307,7 +320,9 @@ void connection_state_machine(server *srv, connection *con) { break; case CON_STATE_READ_REQUEST_CONTENT: case CON_STATE_HANDLE_RESPONSE_HEADER: - TRACE(srv, "%s", "read request/handle response header"); + if (CORE_OPTION(CORE_OPTION_DEBUG_REQUEST_HANDLING)) { + TRACE(srv, "%s", "read request/handle response header"); + } parse_request_body(srv, con); /* TODO: call plugin content_handler */ switch (action_execute(srv, con)) { @@ -331,10 +346,14 @@ void connection_state_machine(server *srv, connection *con) { if (!con->response_headers_sent) { con->response_headers_sent = TRUE; - TRACE(srv, "%s", "write response headers"); + if (CORE_OPTION(CORE_OPTION_DEBUG_REQUEST_HANDLING)) { + TRACE(srv, "%s", "write response headers"); + } response_send_headers(srv, con); } - TRACE(srv, "%s", "write response"); + if (CORE_OPTION(CORE_OPTION_DEBUG_REQUEST_HANDLING)) { + TRACE(srv, "%s", "write response"); + } parse_request_body(srv, con); /* TODO: call plugin content_handler */ forward_response_body(srv, con); @@ -346,7 +365,9 @@ void connection_state_machine(server *srv, connection *con) { if (con->state == CON_STATE_WRITE_RESPONSE) done = TRUE; break; case CON_STATE_RESPONSE_END: - TRACE(srv, "response end (keep_alive = %i)", con->keep_alive); + if (CORE_OPTION(CORE_OPTION_DEBUG_REQUEST_HANDLING)) { + TRACE(srv, "response end (keep_alive = %i)", con->keep_alive); + } /* TODO: call plugin callbacks */ if (con->keep_alive) { connection_reset_keep_alive(srv, con); @@ -356,13 +377,17 @@ void connection_state_machine(server *srv, connection *con) { } break; case CON_STATE_CLOSE: - TRACE(srv, "%s", "connection closed"); + if (CORE_OPTION(CORE_OPTION_DEBUG_REQUEST_HANDLING)) { + TRACE(srv, "%s", "connection closed"); + } /* TODO: call plugin callbacks */ con_put(srv, con); done = TRUE; break; case CON_STATE_ERROR: - TRACE(srv, "%s", "connection closed (error)"); + if (CORE_OPTION(CORE_OPTION_DEBUG_REQUEST_HANDLING)) { + TRACE(srv, "%s", "connection closed (error)"); + } /* TODO: call plugin callbacks */ con_put(srv, con); done = TRUE; diff --git a/src/connection.h b/src/connection.h index 4e2abe0..ebee114 100644 --- a/src/connection.h +++ b/src/connection.h @@ -79,7 +79,7 @@ struct connection { action_stack action_stack; - gpointer *options; /* TODO: options */ + gpointer *options; request request; physical physical; diff --git a/src/lighttpd.c b/src/lighttpd.c index 2014a4f..745c8f7 100644 --- a/src/lighttpd.c +++ b/src/lighttpd.c @@ -53,8 +53,6 @@ int main(int argc, char *argv[]) { srv = server_new(); - log_init(srv); - plugin_register(srv, "core", plugin_core_init); /* if no path is specified for the config, read lighttpd.conf from current directory */ @@ -115,19 +113,9 @@ int main(int argc, char *argv[]) { log_warning(srv, NULL, "test %s", "foo1"); /* duplicate won't be logged */ log_warning(srv, NULL, "test %s", "foo2"); log_debug(srv, NULL, "test %s", "message"); - log_thread_start(srv); server_start(srv); - log_error(srv, NULL, "error %d", 23); - g_atomic_int_set(&srv->rotate_logs, TRUE); - log_warning(srv, NULL, "test %s", "foo3"); - log_warning(srv, NULL, "test %s", "foo4"); - - g_atomic_int_set(&srv->exiting, TRUE); - log_thread_wakeup(srv); - g_thread_join(srv->log_thread); - server_free(srv); return 0; diff --git a/src/log.h b/src/log.h index ee8a8f4..3d68cad 100644 --- a/src/log.h +++ b/src/log.h @@ -16,6 +16,9 @@ LI_API const char *remove_path(const char *path); #define ERROR(srv, fmt, ...) \ log_write(srv, NULL, "%s.%d: (error) "fmt, REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__) +#define INFO(srv, ...) \ + log_write(srv, NULL, __VA_ARGS__) + #define TRACE(srv, fmt, ...) \ log_write(srv, NULL, "%s.%d: (trace) "fmt, REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__) diff --git a/src/network.c b/src/network.c index e8abdb3..b789ee0 100644 --- a/src/network.c +++ b/src/network.c @@ -49,6 +49,7 @@ network_status_t network_write(server *srv, connection *con, int fd, chunkqueue #endif return len ? NETWORK_STATUS_SUCCESS : NETWORK_STATUS_WAIT_FOR_EVENT; case ECONNRESET: + case EPIPE: return NETWORK_STATUS_CONNECTION_CLOSE; default: CON_ERROR(srv, con, "oops, write to fd=%d failed: %s (%d)", fd, strerror(errno), errno ); diff --git a/src/options.c b/src/options.c index af58331..4998c68 100644 --- a/src/options.c +++ b/src/options.c @@ -122,7 +122,7 @@ void option_list_free(GArray *optlist) { g_array_free(optlist, TRUE); } -/* Extract value from option, destroy option */ +/* Extract value from option, option set to none */ gpointer option_extract_value(option *opt) { gpointer val = NULL; if (!opt) return NULL; @@ -153,6 +153,5 @@ gpointer option_extract_value(option *opt) { break; } opt->type = OPTION_NONE; - g_slice_free(option, opt); return val; } diff --git a/src/options.h b/src/options.h index 66ffd4c..14b7537 100644 --- a/src/options.h +++ b/src/options.h @@ -62,7 +62,7 @@ LI_API const char* option_type_string(option_type type); LI_API void option_list_free(GArray *optlist); -/* Extract value from option, destroy option */ +/* Extract value from option, option set to none */ LI_API gpointer option_extract_value(option *opt); #endif diff --git a/src/plugin.c b/src/plugin.c index 8209ea0..ce13c13 100644 --- a/src/plugin.c +++ b/src/plugin.c @@ -50,6 +50,11 @@ static void plugin_free_setups(server *srv, plugin *p) { void plugin_free(server *srv, plugin *p) { if (!p) return; + if (srv->state == SERVER_RUNNING) { + ERROR(srv, "Cannot free plugin '%s' while server is running", p->name); + return; + } + g_hash_table_remove(srv->plugins, p->name); plugin_free_options(srv, p); plugin_free_actions(srv, p); @@ -66,6 +71,11 @@ gboolean plugin_register(server *srv, const gchar *name, PluginInit init) { return FALSE; } + if (srv->state != SERVER_STARTING) { + ERROR(srv, "Cannot register plugin '%s' after server was started", name); + return FALSE; + } + if (g_hash_table_lookup(srv->plugins, name)) { ERROR(srv, "Module '%s' already registered", name); return FALSE; @@ -75,6 +85,7 @@ gboolean plugin_register(server *srv, const gchar *name, PluginInit init) { g_hash_table_insert(srv->plugins, (gchar*) p->name, p); init(srv, p); + p->opt_base_index = g_hash_table_size(srv->options); if (p->options) { size_t i; diff --git a/src/plugin.h b/src/plugin.h index 94f0203..e119d35 100644 --- a/src/plugin.h +++ b/src/plugin.h @@ -47,6 +47,8 @@ struct plugin { gpointer data; /**< private plugin data */ + size_t opt_base_index; + PluginFree free; /**< called before plugin is unloaded */ const plugin_option *options; @@ -110,9 +112,16 @@ LI_API void release_option(server *srv, option_set *mark); /**< Does not free th /* Needed for config frontends */ /** For parsing 'somemod.option = "somevalue"' */ LI_API action* option_action(server *srv, const gchar *name, option *value); -/** For parsing 'somemod.action value', e.g. 'rewrite "/url" => "/destination"' */ +/** For parsing 'somemod.action value', e.g. 'rewrite "/url" => "/destination"' + * You need to free the option after it (it should be of type NONE then) + */ LI_API action* create_action(server *srv, const gchar *name, option *value); /** For setup function, e.g. 'listen "127.0.0.1:8080"' */ LI_API gboolean call_setup(server *srv, const char *name, option *opt); +/* needs connection *con and plugin *p */ +#define OPTION(idx) _OPTION(con, p, idx) +#define _OPTION(con, p, idx) (con->options[p->opt_base_index + idx]) +#define _OPTION_ABS(con, idx) (con->options[idx]) + #endif diff --git a/src/plugin_core.c b/src/plugin_core.c index 5d2b1a5..5b3ca3f 100644 --- a/src/plugin_core.c +++ b/src/plugin_core.c @@ -1,5 +1,6 @@ #include "base.h" +#include "plugin_core.h" static action* core_list(server *srv, plugin* p, option *opt) { action *a; @@ -63,6 +64,30 @@ static action* core_when(server *srv, plugin* p, option *opt) { return a; } +static action* core_set(server *srv, plugin* p, option *opt) { + option *value, *opt_name; + action *a; + UNUSED(p); + + if (opt->type != OPTION_LIST) { + ERROR(srv, "expected list, got %s", option_type_string(opt->type)); + return NULL; + } + if (opt->value.opt_list->len != 2) { + ERROR(srv, "expected list with length 2, has length %u", opt->value.opt_list->len); + return NULL; + } + opt_name = g_array_index(opt->value.opt_list, option*, 0); + value = g_array_index(opt->value.opt_list, option*, 1); + if (opt_name->type != OPTION_STRING) { + ERROR(srv, "expected string as first parameter, got %s", option_type_string(opt_name->type)); + return NULL; + } + a = option_action(srv, opt_name->value.opt_string->str, value); + option_free(opt); + return a; +} + static action_result core_handle_static(server *srv, connection *con, gpointer param) { UNUSED(param); /* TODO: handle static files */ @@ -154,18 +179,22 @@ static gboolean core_listen(server *srv, plugin* p, option *opt) { } TRACE(srv, "will listen to '%s'", opt->value.opt_string->str); + option_free(opt); return TRUE; } static const plugin_option options[] = { - { "static-file.exclude", OPTION_LIST, NULL, NULL }, + { "debug.log-request-handling", OPTION_BOOLEAN, NULL, NULL}, { "log.level", OPTION_STRING, NULL, NULL }, + + { "static-file.exclude", OPTION_LIST, NULL, NULL }, { NULL, 0, NULL, NULL } }; static const plugin_action actions[] = { { "list", core_list }, { "when", core_when }, + { "set", core_set }, { "static", core_static }, { "test", core_test }, { NULL, NULL } diff --git a/src/server.c b/src/server.c index c0729c0..046d2df 100644 --- a/src/server.c +++ b/src/server.c @@ -54,6 +54,37 @@ static void server_setup_free(gpointer _ss) { g_slice_free(server_setup, _ss); } +static struct ev_signal + sig_w_INT, + sig_w_TERM, + sig_w_PIPE; + +static void sigint_cb(struct ev_loop *loop, struct ev_signal *w, int revents) { + server *srv = (server*) w->data; + UNUSED(revents); + + if (!srv->exiting) { + INFO(srv, "Got signal, shutdown"); + server_exit(srv); + } else { + INFO(srv, "Got second signal, force shutdown"); + ev_unloop (loop, EVUNLOOP_ALL); + } +} + +static void sigpipe_cb(struct ev_loop *loop, struct ev_signal *w, int revents) { + /* ignore */ + UNUSED(loop); UNUSED(w); UNUSED(revents); +} + +#define CATCH_SIGNAL(loop, cb, n) do {\ + my_ev_init(&sig_w_##n, cb); \ + ev_signal_set(&sig_w_##n, SIG##n); \ + ev_signal_start(loop, &sig_w_##n); \ + sig_w_##n.data = srv; \ + ev_unref(loop); /* Signal watchers shouldn't keep loop alive */ \ +} while (0) + server* server_new() { server* srv = g_slice_new0(server); @@ -65,6 +96,10 @@ server* server_new() { fatal ("could not initialise libev, bad $LIBEV_FLAGS in environment?"); } + CATCH_SIGNAL(srv->loop, sigint_cb, INT); + CATCH_SIGNAL(srv->loop, sigint_cb, TERM); + CATCH_SIGNAL(srv->loop, sigpipe_cb, PIPE); + srv->connections_active = 0; srv->connections = g_array_new(FALSE, TRUE, sizeof(connection*)); srv->sockets = g_array_new(FALSE, TRUE, sizeof(server_socket*)); @@ -83,6 +118,8 @@ server* server_new() { srv->last_generated_date_ts = 0; srv->ts_date_str = g_string_sized_new(255); + log_init(srv); + return srv; } @@ -134,13 +171,16 @@ void server_free(server* srv) { g_string_free(srv->ts_date_str, TRUE); /* free logs */ - GHashTableIter iter; - gpointer k, v; - g_hash_table_iter_init(&iter, srv->logs); - while (g_hash_table_iter_next(&iter, &k, &v)) { - log_free(srv, v); + g_thread_join(srv->log_thread); + { + GHashTableIter iter; + gpointer k, v; + g_hash_table_iter_init(&iter, srv->logs); + while (g_hash_table_iter_next(&iter, &k, &v)) { + log_free(srv, v); + } + g_hash_table_destroy(srv->logs); } - g_hash_table_destroy(srv->logs); g_mutex_free(srv->log_mutex); g_async_queue_unref(srv->log_queue); @@ -229,28 +269,6 @@ void server_listen(server *srv, int fd) { g_array_append_val(srv->sockets, sock); } - -static void sigint_cb(struct ev_loop *loop, struct ev_signal *w, int revents) { - UNUSED(w); UNUSED(revents); - ev_unloop (loop, EVUNLOOP_ALL); -} - -static void sigpipe_cb(struct ev_loop *loop, struct ev_signal *w, int revents) { - /* ignore */ - UNUSED(loop); UNUSED(w); UNUSED(revents); -} - -static struct ev_signal - sig_w_INT, - sig_w_TERM, - sig_w_PIPE; - -#define CATCH_SIGNAL(loop, cb, n) do {\ - my_ev_init(&sig_w_##n, cb); \ - ev_signal_set(&sig_w_##n, SIG##n); \ - ev_signal_start(loop, &sig_w_##n); \ -} while (0) - void server_start(server *srv) { guint i; if (srv->state == SERVER_STOPPING || srv->state == SERVER_RUNNING) return; /* no restart after stop */ @@ -262,14 +280,16 @@ void server_start(server *srv) { return; } + /* TODO: get default values for options */ + srv->option_count = g_hash_table_size(srv->options); + srv->option_def_values = g_slice_alloc0(srv->option_count * sizeof(*srv->option_def_values)); + for (i = 0; i < srv->sockets->len; i++) { server_socket *sock = g_array_index(srv->sockets, server_socket*, i); ev_io_start(srv->loop, &sock->watcher); } - CATCH_SIGNAL(srv->loop, sigint_cb, INT); - CATCH_SIGNAL(srv->loop, sigint_cb, TERM); - CATCH_SIGNAL(srv->loop, sigpipe_cb, PIPE); + log_thread_start(srv); ev_loop(srv->loop, 0); } @@ -286,7 +306,7 @@ void server_stop(server *srv) { } void server_exit(server *srv) { - srv->exiting = TRUE; + g_atomic_int_set(&srv->exiting, TRUE); server_stop(srv); { /* force closing sockets */ @@ -295,8 +315,11 @@ void server_exit(server *srv) { server_rem_closing_socket(srv, (server_closing_socket*) iter->data); } } + + log_thread_wakeup(srv); } + void joblist_append(server *srv, connection *con) { connection_state_machine(srv, con); } diff --git a/src/server.h b/src/server.h index 6ac188b..38921c5 100644 --- a/src/server.h +++ b/src/server.h @@ -39,7 +39,8 @@ struct server { GHashTable *actions; /**< const gchar* => (server_action*) */ GHashTable *setups; /**< const gchar* => (server_setup*) */ - gpointer *option_def_values; /* TODO: options */ + size_t option_count; /**< set to size of option hash table */ + gpointer *option_def_values; struct action *mainaction; gboolean exiting; @@ -65,8 +66,12 @@ LI_API void server_free(server* srv); LI_API void server_listen(server *srv, int fd); +/* Start accepting connection, use log files, no new plugins after that */ LI_API void server_start(server *srv); +/* stop accepting connections, turn keep-alive off */ LI_API void server_stop(server *srv); +/* close connections, close logs, stop log-thread */ +LI_API void server_exit(server *srv); LI_API void joblist_append(server *srv, connection *con);