diff --git a/src/plugin.c b/src/plugin.c index d465d15..27f25bf 100644 --- a/src/plugin.c +++ b/src/plugin.c @@ -232,19 +232,24 @@ void release_option(server *srv, option_set *mark) { /** Does not free the optio /* Nothing to free */ break; case VALUE_STRING: - g_string_free(mark->value.string, TRUE); + if (mark->value.string) + g_string_free(mark->value.string, TRUE); break; case VALUE_LIST: - value_list_free(mark->value.list); + if (mark->value.list) + value_list_free(mark->value.list); break; case VALUE_HASH: - g_hash_table_destroy(mark->value.hash); + if (mark->value.hash) + g_hash_table_destroy(mark->value.hash); break; case VALUE_ACTION: - action_release(srv, mark->value.action); + if (mark->value.action) + action_release(srv, mark->value.action); break; case VALUE_CONDITION: - condition_release(srv, mark->value.cond); + if (mark->value.cond) + condition_release(srv, mark->value.cond); break; } } else { @@ -302,9 +307,11 @@ gboolean call_setup(server *srv, const char *name, value *val) { void plugins_prepare_callbacks(server *srv) { GHashTableIter iter; plugin *p; + gpointer v; g_hash_table_iter_init(&iter, srv->plugins); - while (g_hash_table_iter_next(&iter, NULL, (gpointer*) &p)) { + while (g_hash_table_iter_next(&iter, NULL, &v)) { + p = (plugin*) v; if (p->handle_close) g_array_append_val(srv->plugins_handle_close, p); } @@ -318,3 +325,57 @@ void plugins_handle_close(connection *con) { p->handle_close(con, p); } } + +gboolean plugins_load_default_options(server *srv) { + GHashTableIter iter; + gpointer k, v; + + g_hash_table_iter_init(&iter, srv->options); + while (g_hash_table_iter_next(&iter, &k, &v)) { + server_option *sopt = v; + option_value oval = { 0 }; + + if (!sopt->parse_option) { + switch (sopt->type) { + case VALUE_NONE: + break; + case VALUE_BOOLEAN: + oval.boolean = GPOINTER_TO_INT(sopt->default_value); + case VALUE_NUMBER: + oval.number = GPOINTER_TO_INT(sopt->default_value); + break; + case VALUE_STRING: + oval.string = g_string_new((const char*) sopt->default_value); + break; + default: + oval.ptr = NULL; + } + } else { + if (!sopt->parse_option(srv, sopt->p, sopt->module_index, NULL, &oval)) { + /* errors should be logged by parse function */ + return FALSE; + } + } + srv->option_def_values[sopt->index] = oval; + } + return TRUE; +} + +void plugins_free_default_options(server *srv) { + static const option_value oempty = {0}; + GHashTableIter iter; + gpointer k, v; + + g_hash_table_iter_init(&iter, srv->options); + while (g_hash_table_iter_next(&iter, &k, &v)) { + server_option *sopt = v; + option_set mark; + mark.sopt = sopt; + mark.ndx = sopt->index; + mark.value = srv->option_def_values[sopt->index]; + + release_option(srv, &mark); + srv->option_def_values[sopt->index] = oempty; + } + return TRUE; +} diff --git a/src/plugin.h b/src/plugin.h index 09f52e5..1f3365d 100644 --- a/src/plugin.h +++ b/src/plugin.h @@ -38,7 +38,6 @@ typedef void (*PluginInit) (server *srv, plugin *p); typedef void (*PluginFree) (server *srv, plugin *p); typedef gboolean (*PluginParseOption) (server *srv, plugin *p, size_t ndx, value *val, option_value *oval); typedef void (*PluginFreeOption) (server *srv, plugin *p, size_t ndx, option_value oval); -typedef gpointer (*PluginDefaultValue) (server *srv, plugin *p, gsize ndx); typedef action* (*PluginCreateAction) (server *srv, plugin *p, value *val); typedef gboolean (*PluginSetup) (server *srv, plugin *p, value *val); @@ -77,7 +76,7 @@ struct plugin_option { const gchar *name; value_type type; - PluginDefaultValue default_value; + gpointer default_value; PluginParseOption parse_option; PluginFreeOption free_option; }; @@ -96,16 +95,28 @@ struct plugin_setup { struct server_option { plugin *p; - /** the plugin must free the _content_ of the value + /** the plugin must free the _content_ of the value (e.g. with option_free) * val is zero to get the global default value if nothing is specified * save result in value * - * Default behaviour (NULL) is to just use the value as value + * Default behaviour (NULL) is to extract the inner value from val */ - PluginDefaultValue default_value; /* default value callback - if no callback is provided, default value will be NULL, 0 or FALSE */ PluginParseOption parse_option; + + /** the free_option handler has to free all allocated resources; + * it may get called with 0 initialized options, so you have to + * check the value. + */ PluginFreeOption free_option; + /** if parse_option is NULL, the default_value is used; it is only used + * for the following value types: + * - BOOLEAN, NUMBER: casted with GPOINTER_TO_INT, i.e. set it with GINT_TO_POINTER + * the numbers are limited to the 32-bit range according to the glib docs + * - STRING: used for g_string_new, i.e. a const char* + */ + gpointer default_value; + size_t index, module_index; value_type type; }; @@ -143,6 +154,9 @@ LI_API action* create_action(server *srv, const gchar *name, value *value); /** For setup function, e.g. 'listen "127.0.0.1:8080"' */ LI_API gboolean call_setup(server *srv, const char *name, value *val); +LI_API gboolean plugins_load_default_options(server *srv); +LI_API void plugins_free_default_options(server *srv); + /* 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]) diff --git a/src/plugin_core.c b/src/plugin_core.c index 84cba55..2b0d907 100644 --- a/src/plugin_core.c +++ b/src/plugin_core.c @@ -419,32 +419,7 @@ static gboolean core_workers(server *srv, plugin* p, value *val) { return TRUE; } -gpointer core_option_max_keep_alive_idle_default(server *srv, plugin *p, gsize ndx) { - UNUSED(srv); - UNUSED(p); - UNUSED(ndx); - - return GINT_TO_POINTER(5); -} - -gpointer core_option_server_tag_default(server *srv, plugin *p, gsize ndx) { - UNUSED(srv); - UNUSED(p); - UNUSED(ndx); - - return g_string_new_len(CONST_STR_LEN("lighttpd-2.0~sandbox")); /* TODO: fix mem leak */ -} - -gpointer core_option_log_default(server *srv, plugin *p, gsize ndx) { - UNUSED(srv); - UNUSED(p); - UNUSED(ndx); - - GArray *arr = g_array_sized_new(FALSE, TRUE, sizeof(log_t*), 5); - return arr; -} - -gboolean core_option_log_parse(server *srv, plugin *p, size_t ndx, value *val, option_value *oval) { +static gboolean core_option_log_parse(server *srv, plugin *p, size_t ndx, value *val, option_value *oval) { GHashTableIter iter; gpointer k, v; log_level_t level; @@ -454,7 +429,9 @@ gboolean core_option_log_parse(server *srv, plugin *p, size_t ndx, value *val, o UNUSED(p); UNUSED(ndx); + oval->list = arr; g_array_set_size(arr, 5); + if (!val) return TRUE; /* default value */ g_hash_table_iter_init(&iter, val->data.hash); while (g_hash_table_iter_next(&iter, &k, &v)) { @@ -476,36 +453,38 @@ gboolean core_option_log_parse(server *srv, plugin *p, size_t ndx, value *val, o } } - oval->list = arr; - return TRUE; } -void core_option_log_free(server *srv, plugin *p, size_t ndx, option_value oval) { +static void core_option_log_free(server *srv, plugin *p, size_t ndx, option_value oval) { UNUSED(p); UNUSED(ndx); GArray *arr = oval.list; + if (!arr) return; for (guint i = 0; i < arr->len; i++) { if (NULL != g_array_index(arr, log_t*, i)) log_unref(srv, g_array_index(arr, log_t*, i)); } + g_array_free(arr, TRUE); } -gboolean core_option_log_timestamp_parse(server *srv, plugin *p, size_t ndx, value *val, option_value *oval) { +static gboolean core_option_log_timestamp_parse(server *srv, plugin *p, size_t ndx, value *val, option_value *oval) { UNUSED(p); UNUSED(ndx); + if (!val) return TRUE; oval->ptr = log_timestamp_new(srv, val->data.string); return TRUE; } -void core_option_log_timestamp_free(server *srv, plugin *p, size_t ndx, option_value oval) { +static void core_option_log_timestamp_free(server *srv, plugin *p, size_t ndx, option_value oval) { UNUSED(p); UNUSED(ndx); + if (!oval.ptr) return; log_timestamp_free(srv, oval.ptr); } @@ -513,12 +492,12 @@ static const plugin_option options[] = { { "debug.log_request_handling", VALUE_BOOLEAN, NULL, NULL, NULL }, { "log.timestamp", VALUE_STRING, NULL, core_option_log_timestamp_parse, core_option_log_timestamp_free }, - { "log", VALUE_HASH, core_option_log_default, core_option_log_parse, core_option_log_free }, + { "log", VALUE_HASH, NULL, core_option_log_parse, core_option_log_free }, { "static-file.exclude", VALUE_LIST, NULL, NULL, NULL }, - { "server.tag", VALUE_STRING, core_option_server_tag_default, NULL, NULL }, - { "server.max_keep_alive_idle", VALUE_NUMBER, core_option_max_keep_alive_idle_default, NULL, NULL }, + { "server.tag", VALUE_STRING, "lighttpd-2.0~sandbox", NULL, NULL }, + { "server.max_keep_alive_idle", VALUE_NUMBER, GINT_TO_POINTER(5), NULL, NULL }, { NULL, 0, NULL, NULL, NULL } }; diff --git a/src/server.c b/src/server.c index 177434d..84f5569 100644 --- a/src/server.c +++ b/src/server.c @@ -122,12 +122,14 @@ void server_free(server* srv) { action_release(srv, srv->mainaction); + if (srv->option_def_values) { + plugins_free_default_options(srv); + g_slice_free1(srv->option_count * sizeof(*srv->option_def_values), srv->option_def_values); + } + server_plugins_free(srv); g_array_free(srv->plugins_handle_close, TRUE); /* TODO: */ - if (srv->option_def_values) - g_slice_free1(srv->option_count * sizeof(*srv->option_def_values), srv->option_def_values); - /* free logs */ g_thread_join(srv->logs.thread); { @@ -255,8 +257,6 @@ void server_listen(server *srv, int fd) { void server_start(server *srv) { guint i; - GHashTableIter iter; - gpointer k, v; server_state srvstate = g_atomic_int_get(&srv->state); if (srvstate == SERVER_STOPPING || srvstate == SERVER_RUNNING) return; /* no restart after stop */ g_atomic_int_set(&srv->state, SERVER_RUNNING); @@ -273,11 +273,10 @@ void server_start(server *srv) { srv->option_def_values = g_slice_alloc0(srv->option_count * sizeof(*srv->option_def_values)); /* set default option values */ - g_hash_table_iter_init(&iter, srv->options); - while (g_hash_table_iter_next(&iter, &k, &v)) { - server_option *so = v; - if (so->default_value) - srv->option_def_values[so->index].ptr = so->default_value(srv, so->p, so->index); + if (!plugins_load_default_options(srv)) { + ERROR(srv, "%s", "Error while loading option default values"); + server_stop(srv); + return; } plugins_prepare_callbacks(srv);