From: Timo Sirainen Date: Sat, 20 Feb 2010 15:16:41 +0000 (+0200) Subject: lib-master: Added support for caching config lookups. X-Git-Tag: 2.0.beta3~5 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=5d03d9f439e41c90215a3c938ffebe4c2a8ae257;p=thirdparty%2Fdovecot%2Fcore.git lib-master: Added support for caching config lookups. Currently caching won't work if config has any remote {} blocks. --HG-- branch : HEAD --- diff --git a/src/config/config-connection.c b/src/config/config-connection.c index 94cced4d5b..4e1943c8da 100644 --- a/src/config/config-connection.c +++ b/src/config/config-connection.c @@ -6,6 +6,7 @@ #include "ostream.h" #include "settings-parser.h" #include "master-service.h" +#include "master-service-settings.h" #include "config-request.h" #include "config-parser.h" #include "config-connection.h" @@ -15,7 +16,7 @@ #define MAX_INBUF_SIZE 1024 -#define CONFIG_CLIENT_PROTOCOL_MAJOR_VERSION 1 +#define CONFIG_CLIENT_PROTOCOL_MAJOR_VERSION 2 #define CONFIG_CLIENT_PROTOCOL_MINOR_VERSION 0 struct config_connection { @@ -65,6 +66,8 @@ config_request_output(const char *key, const char *value, static int config_connection_request(struct config_connection *conn, const char *const *args) { + struct config_export_context *ctx; + struct master_service_settings_output output; struct config_filter filter; const char *path, *error, *module = ""; @@ -106,8 +109,22 @@ static int config_connection_request(struct config_connection *conn, } o_stream_cork(conn->output); - if (config_request_handle(&filter, module, CONFIG_DUMP_SCOPE_SET, 0, - config_request_output, conn->output) < 0) { + + ctx = config_export_init(&filter, module, CONFIG_DUMP_SCOPE_SET, 0, + config_request_output, conn->output); + config_export_get_output(ctx, &output); + + if (output.service_uses_local) + o_stream_send_str(conn->output, "service-uses-local\t"); + if (output.service_uses_remote) + o_stream_send_str(conn->output, "service-uses-remote\t"); + if (output.used_local) + o_stream_send_str(conn->output, "used-local\t"); + if (output.used_remote) + o_stream_send_str(conn->output, "used-remote\t"); + o_stream_send_str(conn->output, "\n"); + + if (config_export_finish(&ctx) < 0) { config_connection_destroy(conn); return -1; } diff --git a/src/config/config-filter.c b/src/config/config-filter.c index b63dbf5a14..1866e49eca 100644 --- a/src/config/config-filter.c +++ b/src/config/config-filter.c @@ -3,6 +3,7 @@ #include "lib.h" #include "array.h" #include "settings-parser.h" +#include "master-service-settings.h" #include "config-parser.h" #include "config-filter.h" @@ -11,8 +12,8 @@ struct config_filter_context { struct config_filter_parser *const *parsers; }; -bool config_filter_match(const struct config_filter *mask, - const struct config_filter *filter) +static bool config_filter_match_service(const struct config_filter *mask, + const struct config_filter *filter) { if (mask->service != NULL) { if (filter->service == NULL) @@ -26,6 +27,12 @@ bool config_filter_match(const struct config_filter *mask, return FALSE; } } + return TRUE; +} + +static bool config_filter_match_rest(const struct config_filter *mask, + const struct config_filter *filter) +{ if (mask->local_host != NULL) { if (filter->local_host == NULL) return FALSE; @@ -56,6 +63,15 @@ bool config_filter_match(const struct config_filter *mask, return TRUE; } +bool config_filter_match(const struct config_filter *mask, + const struct config_filter *filter) +{ + if (!config_filter_match_service(mask, filter)) + return FALSE; + + return config_filter_match_rest(mask, filter); +} + bool config_filters_equal(const struct config_filter *f1, const struct config_filter *f2) { @@ -134,15 +150,32 @@ config_filter_parser_cmp(struct config_filter_parser *const *p1, static struct config_filter_parser *const * config_filter_find_all(struct config_filter_context *ctx, - const struct config_filter *filter) + const struct config_filter *filter, + struct master_service_settings_output *output_r) { ARRAY_TYPE(config_filter_parsers) matches; unsigned int i; + memset(output_r, 0, sizeof(*output_r)); + t_array_init(&matches, 8); for (i = 0; ctx->parsers[i] != NULL; i++) { - if (config_filter_match(&ctx->parsers[i]->filter, filter)) + const struct config_filter *mask = &ctx->parsers[i]->filter; + + if (!config_filter_match_service(mask, filter)) + continue; + + if (mask->local_bits > 0) + output_r->service_uses_local = TRUE; + if (mask->remote_bits > 0) + output_r->service_uses_remote = TRUE; + if (config_filter_match_rest(mask, filter)) { + if (mask->local_bits > 0) + output_r->used_local = TRUE; + if (mask->remote_bits > 0) + output_r->used_remote = TRUE; array_append(&matches, &ctx->parsers[i], 1); + } } array_sort(&matches, config_filter_parser_cmp); (void)array_append_space(&matches); @@ -187,6 +220,7 @@ config_module_parser_apply_changes(struct config_module_parser *dest, int config_filter_parsers_get(struct config_filter_context *ctx, pool_t pool, const struct config_filter *filter, struct config_module_parser **parsers_r, + struct master_service_settings_output *output_r, const char **error_r) { struct config_filter_parser *const *src; @@ -194,7 +228,7 @@ int config_filter_parsers_get(struct config_filter_context *ctx, pool_t pool, const char *error, **error_p; unsigned int i, count; - src = config_filter_find_all(ctx, filter); + src = config_filter_find_all(ctx, filter, output_r); /* all of them should have the same number of parsers. duplicate our initial parsers from the first match */ diff --git a/src/config/config-filter.h b/src/config/config-filter.h index bec0f46e21..d2156559e0 100644 --- a/src/config/config-filter.h +++ b/src/config/config-filter.h @@ -3,6 +3,8 @@ #include "network.h" +struct master_service_settings_output; + struct config_filter { const char *service; const char *local_host, *remote_host; @@ -29,6 +31,7 @@ void config_filter_add_all(struct config_filter_context *ctx, int config_filter_parsers_get(struct config_filter_context *ctx, pool_t pool, const struct config_filter *filter, struct config_module_parser **parsers_r, + struct master_service_settings_output *output_r, const char **error_r); void config_filter_parsers_free(struct config_module_parser *parsers); diff --git a/src/config/config-parser.c b/src/config/config-parser.c index 05d4141f75..034006f297 100644 --- a/src/config/config-parser.c +++ b/src/config/config-parser.c @@ -9,6 +9,7 @@ #include "module-dir.h" #include "settings-parser.h" #include "service-settings.h" +#include "master-service-settings.h" #include "all-settings.h" #include "config-filter.h" #include "config-request.h" @@ -321,6 +322,7 @@ config_all_parsers_check(struct parser_context *ctx, { struct config_filter_parser *const *parsers; struct config_module_parser *tmp_parsers; + struct master_service_settings_output output; unsigned int i, count; pool_t tmp_pool; int ret = 0; @@ -332,7 +334,8 @@ config_all_parsers_check(struct parser_context *ctx, for (i = 0; i < count && ret == 0; i++) { if (config_filter_parsers_get(new_filter, tmp_pool, &parsers[i]->filter, - &tmp_parsers, error_r) < 0) { + &tmp_parsers, &output, + error_r) < 0) { ret = -1; break; } diff --git a/src/config/config-request.c b/src/config/config-request.c index 75875227dc..29f0c15b8a 100644 --- a/src/config/config-request.c +++ b/src/config/config-request.c @@ -11,7 +11,7 @@ #include "config-parser.h" #include "config-request.h" -struct settings_export_context { +struct config_export_context { pool_t pool; string_t *value; string_t *prefix; @@ -21,7 +21,12 @@ struct settings_export_context { config_request_callback_t *callback; void *context; + const char *module; enum config_dump_flags flags; + struct config_module_parser *parsers; + struct master_service_settings_output output; + + bool failed; }; static bool parsers_are_connected(const struct setting_parser_info *root, @@ -157,7 +162,7 @@ bool config_export_type(string_t *str, const void *value, } static void -settings_export(struct settings_export_context *ctx, +settings_export(struct config_export_context *ctx, const struct setting_parser_info *info, bool parent_unique_deflist, const void *set, const void *change_set) @@ -305,53 +310,85 @@ settings_export(struct settings_export_context *ctx, } } -int config_request_handle(const struct config_filter *filter, - const char *module, enum config_dump_scope scope, - enum config_dump_flags flags, - config_request_callback_t *callback, void *context) +struct config_export_context * +config_export_init(const struct config_filter *filter, + const char *module, enum config_dump_scope scope, + enum config_dump_flags flags, + config_request_callback_t *callback, void *context) +{ + struct config_export_context *ctx; + const char *error; + pool_t pool; + + pool = pool_alloconly_create("config export", 1024*64); + ctx = p_new(pool, struct config_export_context, 1); + ctx->pool = pool; + + ctx->module = p_strdup(pool, module); + ctx->flags = flags; + ctx->callback = callback; + ctx->context = context; + ctx->scope = scope; + ctx->value = t_str_new(256); + ctx->prefix = t_str_new(64); + ctx->keys = hash_table_create(default_pool, ctx->pool, 0, + str_hash, (hash_cmp_callback_t *)strcmp); + + if (config_filter_parsers_get(config_filter, ctx->pool, filter, + &ctx->parsers, &ctx->output, + &error) < 0) { + i_error("%s", error); + ctx->failed = TRUE; + } + return ctx; +} + +void config_export_get_output(struct config_export_context *ctx, + struct master_service_settings_output *output_r) +{ + *output_r = ctx->output; +} + +static void config_export_free(struct config_export_context *ctx) { - struct config_module_parser *parsers, *parser; - struct settings_export_context ctx; + if (ctx->parsers != NULL) + config_filter_parsers_free(ctx->parsers); + hash_table_destroy(&ctx->keys); + pool_unref(&ctx->pool); +} + +int config_export_finish(struct config_export_context **_ctx) +{ + struct config_export_context *ctx = *_ctx; + struct config_module_parser *parser; const char *error; unsigned int i; int ret = 0; - memset(&ctx, 0, sizeof(ctx)); - ctx.pool = pool_alloconly_create("config request", 1024*64); + *_ctx = NULL; - if (config_filter_parsers_get(config_filter, ctx.pool, filter, - &parsers, &error) < 0) { - i_error("%s", error); - pool_unref(&ctx.pool); + if (ctx->failed) { + config_export_free(ctx); return -1; } - ctx.flags = flags; - ctx.callback = callback; - ctx.context = context; - ctx.scope = scope; - ctx.value = t_str_new(256); - ctx.prefix = t_str_new(64); - ctx.keys = hash_table_create(default_pool, ctx.pool, 0, - str_hash, (hash_cmp_callback_t *)strcmp); - - for (i = 0; parsers[i].root != NULL; i++) { - parser = &parsers[i]; - if (*module != '\0' && - !config_module_parser_is_in_service(parser, module)) + for (i = 0; ctx->parsers[i].root != NULL; i++) { + parser = &ctx->parsers[i]; + if (*ctx->module != '\0' && + !config_module_parser_is_in_service(parser, ctx->module)) continue; - settings_export(&ctx, parser->root, FALSE, + settings_export(ctx, parser->root, FALSE, settings_parser_get(parser->parser), settings_parser_get_changes(parser->parser)); - if ((flags & CONFIG_DUMP_FLAG_CHECK_SETTINGS) != 0) { + if ((ctx->flags & CONFIG_DUMP_FLAG_CHECK_SETTINGS) != 0) { settings_parse_var_skip(parser->parser); - if (!settings_parser_check(parser->parser, ctx.pool, + if (!settings_parser_check(parser->parser, ctx->pool, &error)) { - if ((flags & CONFIG_DUMP_FLAG_CALLBACK_ERRORS) != 0) { - callback(NULL, error, CONFIG_KEY_ERROR, - context); + if ((ctx->flags & CONFIG_DUMP_FLAG_CALLBACK_ERRORS) != 0) { + ctx->callback(NULL, error, CONFIG_KEY_ERROR, + ctx->context); } else { i_error("%s", error); ret = -1; @@ -360,8 +397,6 @@ int config_request_handle(const struct config_filter *filter, } } } - config_filter_parsers_free(parsers); - hash_table_destroy(&ctx.keys); - pool_unref(&ctx.pool); + config_export_free(ctx); return ret; } diff --git a/src/config/config-request.h b/src/config/config-request.h index bbc97b266a..85f40fbb30 100644 --- a/src/config/config-request.h +++ b/src/config/config-request.h @@ -4,6 +4,7 @@ #include "config-filter.h" enum setting_type; +struct master_service_settings_output; enum config_dump_scope { /* Dump all settings */ @@ -36,9 +37,13 @@ bool config_export_type(string_t *str, const void *value, const void *default_value, enum setting_type type, bool dump_default, bool *dump_r); -int config_request_handle(const struct config_filter *filter, - const char *module, enum config_dump_scope scope, - enum config_dump_flags flags, - config_request_callback_t *callback, void *context); +struct config_export_context * +config_export_init(const struct config_filter *filter, + const char *module, enum config_dump_scope scope, + enum config_dump_flags flags, + config_request_callback_t *callback, void *context); +void config_export_get_output(struct config_export_context *ctx, + struct master_service_settings_output *output_r); +int config_export_finish(struct config_export_context **ctx); #endif diff --git a/src/config/doveconf.c b/src/config/doveconf.c index b488dd3c88..87e2c41c50 100644 --- a/src/config/doveconf.c +++ b/src/config/doveconf.c @@ -114,6 +114,7 @@ static int config_connection_request_human(struct ostream *output, static const char *indent_str = " "; ARRAY_TYPE(const_string) prefixes_arr; ARRAY_TYPE(prefix_stack) prefix_stack; + struct config_export_context *export_ctx; struct prefix_stack prefix; struct config_request_get_string_ctx ctx; const char *const *strings, *const *args, *p, *str, *const *prefixes; @@ -127,11 +128,12 @@ static int config_connection_request_human(struct ostream *output, ctx.pool = pool_alloconly_create("config human strings", 10240); i_array_init(&ctx.strings, 256); i_array_init(&ctx.errors, 256); - if (config_request_handle(filter, module, scope, - CONFIG_DUMP_FLAG_CHECK_SETTINGS | - CONFIG_DUMP_FLAG_HIDE_LIST_DEFAULTS | - CONFIG_DUMP_FLAG_CALLBACK_ERRORS, - config_request_get_strings, &ctx) < 0) + export_ctx = config_export_init(filter, module, scope, + CONFIG_DUMP_FLAG_CHECK_SETTINGS | + CONFIG_DUMP_FLAG_HIDE_LIST_DEFAULTS | + CONFIG_DUMP_FLAG_CALLBACK_ERRORS, + config_request_get_strings, &ctx); + if (config_export_finish(&export_ctx) < 0) return -1; array_sort(&ctx.strings, config_string_cmp); @@ -419,11 +421,14 @@ int main(int argc, char *argv[]) if (ret2 < 0) i_fatal("Errors in configuration"); } else { + struct config_export_context *ctx; + env_put("DOVECONF_ENV=1"); - if (config_request_handle(&filter, module, - CONFIG_DUMP_SCOPE_SET, - CONFIG_DUMP_FLAG_CHECK_SETTINGS, - config_request_putenv, NULL) < 0) + ctx = config_export_init(&filter, module, + CONFIG_DUMP_SCOPE_SET, + CONFIG_DUMP_FLAG_CHECK_SETTINGS, + config_request_putenv, NULL); + if (config_export_finish(&ctx) < 0) i_fatal("Invalid configuration"); execvp(exec_args[0], exec_args); i_fatal("execvp(%s) failed: %m", exec_args[0]); diff --git a/src/lib-master/Makefile.am b/src/lib-master/Makefile.am index c6b3f3d20a..bfa9d985e8 100644 --- a/src/lib-master/Makefile.am +++ b/src/lib-master/Makefile.am @@ -16,6 +16,7 @@ libmaster_la_SOURCES = \ master-login-auth.c \ master-service.c \ master-service-settings.c \ + master-service-settings-cache.c \ syslog-util.c headers = \ diff --git a/src/lib-master/master-service-settings-cache.c b/src/lib-master/master-service-settings-cache.c new file mode 100644 index 0000000000..0206540ab8 --- /dev/null +++ b/src/lib-master/master-service-settings-cache.c @@ -0,0 +1,286 @@ +/* Copyright (c) 2010 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "hash.h" +#include "llist.h" +#include "settings-parser.h" +#include "master-service-private.h" +#include "master-service-settings.h" +#include "master-service-settings-cache.h" + +/* we start with just a guess. it's updated later. */ +#define CACHE_INITIAL_ENTRY_POOL_SIZE (1024*16) +#define CACHE_ADD_ENTRY_POOL_SIZE 1024 + +struct settings_entry { + struct settings_entry *prev, *next; + + pool_t pool; + const char *local_host; + struct ip_addr local_ip; + + struct setting_parser_context *parser; +}; + +struct master_service_settings_cache { + pool_t pool; + + struct master_service *service; + const char *module; + const char *service_name; + size_t max_cache_size; + + /* global settings for this service (after they've been read) */ + struct setting_parser_context *global_parser; + + /* cache for other settings (local_ip/local_host set) */ + struct settings_entry *oldest, *newest; + /* separate list for entries whose parser=global_parser */ + struct settings_entry *oldest_global, *newest_global; + /* local_host, local_ip => struct settings_entry */ + struct hash_table *local_host_hash; + struct hash_table *local_ip_hash; + + /* Initial size for new settings entry pools */ + size_t approx_entry_pool_size; + /* number of bytes malloced by cached settings entries + (doesn't count memory used by hash table or global sets) */ + size_t cache_malloc_size; + + unsigned int done_initial_lookup:1; + unsigned int service_uses_local:1; + unsigned int service_uses_remote:1; +}; + +struct master_service_settings_cache * +master_service_settings_cache_init(struct master_service *service, + const char *module, const char *service_name) +{ + struct master_service_settings_cache *cache; + pool_t pool; + + pool = pool_alloconly_create("master service settings cache", 1024*32); + cache = p_new(pool, struct master_service_settings_cache, 1); + cache->pool = pool; + cache->service = service; + cache->module = p_strdup(pool, module); + cache->service_name = p_strdup(pool, service_name); + cache->max_cache_size = (size_t)-1; + return cache; +} + +void master_service_settings_cache_deinit(struct master_service_settings_cache **_cache) +{ + struct master_service_settings_cache *cache = *_cache; + struct settings_entry *entry, *next; + + for (entry = cache->oldest_global; entry != NULL; entry = next) { + next = entry->next; + pool_unref(&entry->pool); + } + for (entry = cache->oldest; entry != NULL; entry = next) { + next = entry->next; + pool_unref(&entry->pool); + } + if (cache->local_host_hash != NULL) + hash_table_destroy(&cache->local_host_hash); + if (cache->local_ip_hash != NULL) + hash_table_destroy(&cache->local_ip_hash); + pool_unref(&cache->pool); +} + +static bool +cache_can_return_global(struct master_service_settings_cache *cache, + const struct master_service_settings_input *input) +{ + if (cache->service_uses_local) { + if (input->local_host != NULL || input->local_ip.family != 0) + return FALSE; + } + if (cache->service_uses_remote) { + if (input->remote_host != NULL || input->remote_ip.family != 0) + return FALSE; + } + return TRUE; +} + +static bool +cache_find(struct master_service_settings_cache *cache, + const struct master_service_settings_input *input, + const struct setting_parser_context **parser_r) +{ + struct settings_entry *entry; + + if (!cache->done_initial_lookup) + return FALSE; + + if (cache_can_return_global(cache, input)) { + if (cache->global_parser != NULL) { + *parser_r = cache->global_parser; + return TRUE; + } + return FALSE; + } + + if (cache->service_uses_remote) + return FALSE; + + if (cache->local_host_hash != NULL && input->local_host != NULL) { + /* see if we have it already in cache */ + entry = hash_table_lookup(cache->local_host_hash, + input->local_host); + } else if (cache->local_ip_hash != NULL && + input->local_ip.family != 0) { + entry = hash_table_lookup(cache->local_ip_hash, + &input->local_ip); + } else { + entry = NULL; + } + + if (entry != NULL) { + *parser_r = entry->parser; + return TRUE; + } + return FALSE; +} + +static void +setting_entry_detach(struct master_service_settings_cache *cache, + struct settings_entry *entry) +{ + + DLLIST2_REMOVE(&cache->oldest, &cache->newest, entry); + cache->cache_malloc_size -= + pool_alloconly_get_total_alloc_size(entry->pool); + + if (entry->local_host != NULL) + hash_table_remove(cache->local_host_hash, entry->local_host); + if (entry->local_ip.family != 0) + hash_table_remove(cache->local_ip_hash, &entry->local_ip); +} + +static void cache_add(struct master_service_settings_cache *cache, + const struct master_service_settings_input *input, + const struct master_service_settings_output *output, + struct setting_parser_context *parser) +{ + struct settings_entry *entry; + pool_t pool; + size_t pool_size; + char *entry_local_host; + + if (!output->used_local && !output->used_remote) { + /* these are same as global settings */ + if (cache->global_parser == NULL) { + cache->global_parser = + settings_parser_dup(parser, cache->pool); + } + } + if (cache->service_uses_remote) { + /* for now we don't try to handle caching remote IPs */ + return; + } + + if (input->local_host == NULL && input->local_ip.family == 0) + return; + + if (!output->used_local) { + /* use global settings, but add local_ip/host to hash tables + so we'll find them */ + pool = pool_alloconly_create("settings global entry", 128); + entry = p_new(pool, struct settings_entry, 1); + } else if (cache->cache_malloc_size >= cache->max_cache_size) { + /* free the oldest and reuse its pool */ + entry = cache->oldest; + pool = entry->pool; + setting_entry_detach(cache, entry); + p_clear(pool); + } else { + pool_size = cache->approx_entry_pool_size != 0 ? + cache->approx_entry_pool_size : + CACHE_INITIAL_ENTRY_POOL_SIZE; + pool = pool_alloconly_create("settings entry", pool_size); + entry = p_new(pool, struct settings_entry, 1); + } + entry->pool = pool; + entry_local_host = p_strdup(pool, input->local_host); + entry->local_host = entry_local_host; + entry->local_ip = input->local_ip; + if (!output->used_local) { + entry->parser = cache->global_parser; + DLLIST2_PREPEND(&cache->oldest_global, &cache->newest_global, + entry); + } else { + entry->parser = settings_parser_dup(parser, entry->pool); + DLLIST2_PREPEND(&cache->oldest, &cache->newest, entry); + + pool_size = pool_alloconly_get_total_used_size(pool); + if (pool_size > cache->approx_entry_pool_size) { + cache->approx_entry_pool_size = pool_size + + CACHE_ADD_ENTRY_POOL_SIZE; + } + } + cache->cache_malloc_size += pool_alloconly_get_total_alloc_size(pool); + + if (input->local_host != NULL) { + if (cache->local_host_hash == NULL) { + cache->local_host_hash = + hash_table_create(default_pool, cache->pool, 0, + str_hash, + (hash_cmp_callback_t *)strcmp); + } + hash_table_insert(cache->local_host_hash, + entry_local_host, entry); + } + if (input->local_ip.family != 0) { + if (cache->local_ip_hash == NULL) { + cache->local_ip_hash = + hash_table_create(default_pool, cache->pool, 0, + (hash_callback_t *)net_ip_hash, + (hash_cmp_callback_t *)net_ip_cmp); + } + hash_table_insert(cache->local_ip_hash, + &entry->local_ip, entry); + } +} + +int master_service_settings_cache_read(struct master_service_settings_cache *cache, + const struct master_service_settings_input *input, + const struct setting_parser_context **parser_r, + const char **error_r) +{ + struct master_service_settings_output output; + const struct master_service_settings *set; + + i_assert(strcmp(input->module, cache->module) == 0); + i_assert(strcmp(input->service, cache->service_name) == 0); + + if (cache_find(cache, input, parser_r)) + return 0; + + if (master_service_settings_read(cache->service, input, + &output, error_r) < 0) + return -1; + + if (!cache->done_initial_lookup) { + cache->done_initial_lookup = TRUE; + cache->service_uses_local = output.service_uses_local; + cache->service_uses_remote = output.service_uses_remote; + + set = master_service_settings_get(cache->service); + cache->max_cache_size = set->config_cache_size; + } + + if (output.used_local && !cache->service_uses_local) { + *error_r = "BUG: config unexpectedly returned local settings"; + return -1; + } + if (output.used_remote && !cache->service_uses_remote) { + *error_r = "BUG: config unexpectedly returned remote settings"; + return -1; + } + + cache_add(cache, input, &output, cache->service->set_parser); + *parser_r = cache->service->set_parser; + return 0; +} diff --git a/src/lib-master/master-service-settings-cache.h b/src/lib-master/master-service-settings-cache.h new file mode 100644 index 0000000000..200dad4958 --- /dev/null +++ b/src/lib-master/master-service-settings-cache.h @@ -0,0 +1,15 @@ +#ifndef MASTER_SERVICE_SETTINGS_CACHE_H +#define MASTER_SERVICE_SETTINGS_CACHE_H + +struct master_service_settings_cache * +master_service_settings_cache_init(struct master_service *service, + const char *module, + const char *service_name); +void master_service_settings_cache_deinit(struct master_service_settings_cache **cache); + +int master_service_settings_cache_read(struct master_service_settings_cache *cache, + const struct master_service_settings_input *input, + const struct setting_parser_context **parser_r, + const char **error_r); + +#endif diff --git a/src/lib-master/master-service-settings.c b/src/lib-master/master-service-settings.c index 197b487b39..13b89ef0c6 100644 --- a/src/lib-master/master-service-settings.c +++ b/src/lib-master/master-service-settings.c @@ -20,7 +20,7 @@ #define DOVECOT_CONFIG_SOCKET_PATH PKG_RUNDIR"/config" #define CONFIG_READ_TIMEOUT_SECS 10 -#define CONFIG_HANDSHAKE "VERSION\tconfig\t1\t0\n" +#define CONFIG_HANDSHAKE "VERSION\tconfig\t2\t0\n" #undef DEF #define DEF(type, name) \ @@ -32,6 +32,7 @@ static const struct setting_define master_service_setting_defines[] = { DEF(SET_STR, debug_log_path), DEF(SET_STR, log_timestamp), DEF(SET_STR, syslog_facility), + DEF(SET_SIZE, config_cache_size), DEF(SET_BOOL, version_ignore), DEF(SET_BOOL, shutdown_clients), @@ -44,6 +45,7 @@ static const struct master_service_settings master_service_default_settings = { .debug_log_path = "", .log_timestamp = DEFAULT_FAILURE_STAMP_FORMAT, .syslog_facility = "mail", + .config_cache_size = 1024*1024, .version_ignore = FALSE, .shutdown_clients = TRUE }; @@ -218,8 +220,41 @@ master_service_apply_config_overrides(struct master_service *service, return 0; } +static int +config_read_reply_header(struct istream *input, + struct master_service_settings_output *output_r) +{ + const char *line; + ssize_t ret; + + while ((ret = i_stream_read(input)) > 0) { + line = i_stream_next_line(input); + if (line != NULL) + break; + } + if (ret <= 0) + return ret; + + T_BEGIN { + const char *const *arg = t_strsplit(line, "\t"); + + for (; *arg != NULL; arg++) { + if (strcmp(*arg, "service-uses-local") == 0) + output_r->service_uses_local = TRUE; + else if (strcmp(*arg, "service-uses-remote") == 0) + output_r->service_uses_remote = TRUE; + if (strcmp(*arg, "used-local") == 0) + output_r->used_local = TRUE; + else if (strcmp(*arg, "used-remote") == 0) + output_r->used_remote = TRUE; + } + } T_END; + return 1; +} + int master_service_settings_read(struct master_service *service, const struct master_service_settings_input *input, + struct master_service_settings_output *output_r, const char **error_r) { ARRAY_DEFINE(all_roots, const struct setting_parser_info *); @@ -231,7 +266,9 @@ int master_service_settings_read(struct master_service *service, unsigned int i; int ret, fd = -1; time_t now, timeout; - bool standalone_config_from_socket = FALSE; + bool config_socket = FALSE, standalone_config_from_socket = FALSE; + + memset(output_r, 0, sizeof(*output_r)); if (getenv("DOVECONF_ENV") == NULL && (service->flags & MASTER_SERVICE_FLAG_NO_CONFIG_SETTINGS) == 0) { @@ -244,6 +281,7 @@ int master_service_settings_read(struct master_service *service, (void)close(fd); return -1; } + config_socket = TRUE; } if (service->set_pool != NULL) { @@ -279,7 +317,12 @@ int master_service_settings_read(struct master_service *service, timeout = now + CONFIG_READ_TIMEOUT_SECS; do { alarm(timeout - now); - ret = settings_parse_stream_read(parser, istream); + ret = !config_socket ? 1 : + config_read_reply_header(istream, output_r); + if (ret > 0) { + ret = settings_parse_stream_read(parser, + istream); + } alarm(0); if (ret <= 0) break; @@ -358,11 +401,12 @@ int master_service_settings_read_simple(struct master_service *service, const char **error_r) { struct master_service_settings_input input; + struct master_service_settings_output output; memset(&input, 0, sizeof(input)); input.roots = roots; input.module = service->name; - return master_service_settings_read(service, &input, error_r); + return master_service_settings_read(service, &input, &output, error_r); } pool_t master_service_settings_detach(struct master_service *service) diff --git a/src/lib-master/master-service-settings.h b/src/lib-master/master-service-settings.h index 000ab01979..c1d1e86986 100644 --- a/src/lib-master/master-service-settings.h +++ b/src/lib-master/master-service-settings.h @@ -13,6 +13,7 @@ struct master_service_settings { const char *debug_log_path; const char *log_timestamp; const char *syslog_facility; + uoff_t config_cache_size; bool version_ignore; bool shutdown_clients; }; @@ -31,10 +32,22 @@ struct master_service_settings_input { const char *local_host, *remote_host; }; +struct master_service_settings_output { + /* some settings for this service contain local/remote ip/host + specific settings. */ + unsigned int service_uses_local:1; + unsigned int service_uses_remote:1; + /* returned settings contain settings specific to given + local/remote ip/host */ + unsigned int used_local:1; + unsigned int used_remote:1; +}; + extern const struct setting_parser_info master_service_setting_parser_info; int master_service_settings_read(struct master_service *service, const struct master_service_settings_input *input, + struct master_service_settings_output *output_r, const char **error_r); int master_service_settings_read_simple(struct master_service *service, const struct setting_parser_info **roots, diff --git a/src/lib-storage/mail-storage-service.c b/src/lib-storage/mail-storage-service.c index 80a1266043..1c7d0b3c6f 100644 --- a/src/lib-storage/mail-storage-service.c +++ b/src/lib-storage/mail-storage-service.c @@ -14,6 +14,7 @@ #include "auth-master.h" #include "master-service-private.h" #include "master-service-settings.h" +#include "master-service-settings-cache.h" #include "mail-user.h" #include "mail-namespace.h" #include "mail-storage.h" @@ -36,12 +37,19 @@ #define MAX_NOWARN_FORWARD_SECS 10 struct mail_storage_service_ctx { + pool_t pool; struct master_service *service; struct auth_master_connection *conn; struct auth_master_user_list_ctx *auth_list; const struct setting_parser_info **set_roots; enum mail_storage_service_flags flags; + const char *set_cache_module, *set_cache_service; + struct master_service_settings_cache *set_cache; + const struct dynamic_settings_parser *set_cache_dyn_parsers; + struct setting_parser_info *set_cache_dyn_parsers_parent; + const struct setting_parser_info **set_cache_roots; + unsigned int debug:1; }; @@ -418,11 +426,8 @@ mail_storage_service_init_log(struct master_service *service, struct mail_storage_service_user *user) { const struct mail_user_settings *user_set; - void **sets; - - sets = master_service_settings_get_others(service); - user_set = sets[0]; + user_set = master_service_settings_get_others(service)[0]; T_BEGIN { string_t *str; @@ -471,6 +476,7 @@ mail_storage_service_init(struct master_service *service, enum mail_storage_service_flags flags) { struct mail_storage_service_ctx *ctx; + pool_t pool; unsigned int count; (void)umask(0077); @@ -481,7 +487,9 @@ mail_storage_service_init(struct master_service *service, mail_storage_register_all(); mailbox_list_register_all(); - ctx = i_new(struct mail_storage_service_ctx, 1); + pool = pool_alloconly_create("mail storage service", 2048); + ctx = p_new(pool, struct mail_storage_service_ctx, 1); + ctx->pool = pool; ctx->service = service; ctx->flags = flags; @@ -539,8 +547,11 @@ settings_parser_update_children_parent(struct setting_parser_info *parent, static struct setting_parser_info * dyn_parsers_update_parent(pool_t pool, - struct master_service_settings_input *input) + const struct setting_parser_info ***_roots, + const struct dynamic_settings_parser **_dyn_parsers) { + const struct dynamic_settings_parser *dyn_parsers = *_dyn_parsers; + const const struct setting_parser_info **roots = *_roots; const struct setting_parser_info *old_parent, **new_roots; struct setting_parser_info *new_parent, *new_info; struct dynamic_settings_parser *new_dyn_parsers; @@ -549,34 +560,34 @@ dyn_parsers_update_parent(pool_t pool, /* settings_parser_info_update() modifies the parent structure. since we may be using the same structure later, we want it to be in its original state, so we'll have to copy all structures. */ - old_parent = input->dyn_parsers[0].info->parent; + old_parent = dyn_parsers[0].info->parent; new_parent = p_new(pool, struct setting_parser_info, 1); *new_parent = *old_parent; settings_parser_update_children_parent(new_parent, pool); /* update root */ - for (count = 0; input->roots[count] != NULL; count++) ; + for (count = 0; roots[count] != NULL; count++) ; new_roots = p_new(pool, const struct setting_parser_info *, count + 1); for (i = 0; i < count; i++) { - if (input->roots[i] == old_parent) + if (roots[i] == old_parent) new_roots[i] = new_parent; else - new_roots[i] = input->roots[i]; + new_roots[i] = roots[i]; } - input->roots = new_roots; + *_roots = new_roots; /* update parent in dyn_parsers */ - for (count = 0; input->dyn_parsers[count].name != NULL; count++) ; + for (count = 0; dyn_parsers[count].name != NULL; count++) ; new_dyn_parsers = p_new(pool, struct dynamic_settings_parser, count + 1); for (i = 0; i < count; i++) { - new_dyn_parsers[i] = input->dyn_parsers[i]; + new_dyn_parsers[i] = dyn_parsers[i]; new_info = p_new(pool, struct setting_parser_info, 1); - *new_info = *input->dyn_parsers[i].info; + *new_info = *dyn_parsers[i].info; new_info->parent = new_parent; new_dyn_parsers[i].info = new_info; } - input->dyn_parsers = new_dyn_parsers; + *_dyn_parsers = new_dyn_parsers; return new_parent; } @@ -584,21 +595,20 @@ int mail_storage_service_read_settings(struct mail_storage_service_ctx *ctx, const struct mail_storage_service_input *input, pool_t pool, const struct setting_parser_info **user_info_r, + const struct setting_parser_context **parser_r, const char **error_r) { struct master_service_settings_input set_input; + struct master_service_settings_output set_output; unsigned int i; memset(&set_input, 0, sizeof(set_input)); set_input.roots = ctx->set_roots; - set_input.dyn_parsers = mail_storage_get_dynamic_parsers(); /* settings reader may exec doveconf, which is going to clear environment, and if we're not doing a userdb lookup we want to use $HOME */ set_input.preserve_home = (ctx->flags & MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP) == 0; - set_input.dyn_parsers_parent = - dyn_parsers_update_parent(pool, &set_input); if (input != NULL) { set_input.module = input->module; @@ -607,15 +617,47 @@ int mail_storage_service_read_settings(struct mail_storage_service_ctx *ctx, set_input.local_ip = input->local_ip; set_input.remote_ip = input->remote_ip; } - if (master_service_settings_read(ctx->service, &set_input, - error_r) < 0) { - *error_r = t_strdup_printf("Error reading configuration: %s", - *error_r); - return -1; + if (ctx->set_cache == NULL) { + ctx->set_cache_module = p_strdup(ctx->pool, input->module); + ctx->set_cache_service = p_strdup(ctx->pool, input->service); + ctx->set_cache = master_service_settings_cache_init( + ctx->service, input->module, input->service); + ctx->set_cache_roots = ctx->set_roots; + ctx->set_cache_dyn_parsers = + mail_storage_get_dynamic_parsers(ctx->pool); + ctx->set_cache_dyn_parsers_parent = + dyn_parsers_update_parent(ctx->pool, + &ctx->set_cache_roots, + &ctx->set_cache_dyn_parsers); + } + + if (strcmp(input->module, ctx->set_cache_module) == 0 && + strcmp(input->service, ctx->set_cache_service) == 0) { + set_input.roots = ctx->set_cache_roots; + set_input.dyn_parsers = ctx->set_cache_dyn_parsers; + set_input.dyn_parsers_parent = + ctx->set_cache_dyn_parsers_parent; + if (master_service_settings_cache_read(ctx->set_cache, + &set_input, + parser_r, error_r) < 0) + return -1; + } else { + set_input.dyn_parsers = mail_storage_get_dynamic_parsers(pool); + set_input.dyn_parsers_parent = + dyn_parsers_update_parent(pool, &set_input.roots, + &set_input.dyn_parsers); + if (master_service_settings_read(ctx->service, &set_input, + &set_output, error_r) < 0) { + *error_r = t_strdup_printf( + "Error reading configuration: %s", *error_r); + return -1; + } + *parser_r = ctx->service->set_parser; } for (i = 0; ctx->set_roots[i] != NULL; i++) { - if (ctx->set_roots[i] == &mail_user_setting_parser_info) { + if (strcmp(ctx->set_roots[i]->module_name, + mail_user_setting_parser_info.module_name) == 0) { *user_info_r = set_input.roots[i]; return 0; } @@ -684,19 +726,19 @@ int mail_storage_service_lookup(struct mail_storage_service_ctx *ctx, const struct mail_user_settings *user_set; const char *const *userdb_fields; struct auth_user_reply reply; - void **sets; + const struct setting_parser_context *set_parser; pool_t user_pool, temp_pool; int ret = 1; user_pool = pool_alloconly_create("mail storage service user", 1024*5); if (mail_storage_service_read_settings(ctx, input, user_pool, - &user_info, error_r) < 0) { + &user_info, &set_parser, + error_r) < 0) { pool_unref(&user_pool); return -1; } - sets = settings_parser_get_list(ctx->service->set_parser); - user_set = sets[1]; + user_set = settings_parser_get_list(set_parser)[1]; if (ctx->conn == NULL) mail_storage_service_first_init(ctx, user_info, user_set); @@ -725,13 +767,11 @@ int mail_storage_service_lookup(struct mail_storage_service_ctx *ctx, user->input.username = p_strdup(user_pool, username); user->user_info = user_info; - user->set_parser = - settings_parser_dup(ctx->service->set_parser, user_pool); + user->set_parser = settings_parser_dup(set_parser, user_pool); if (!settings_parser_check(user->set_parser, user_pool, error_r)) i_unreached(); - sets = settings_parser_get_list(user->set_parser); - user->user_set = sets[1]; + user->user_set = settings_parser_get_list(user->set_parser)[1]; if ((ctx->flags & MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP) == 0) { const char *home = getenv("HOME"); @@ -871,8 +911,8 @@ void mail_storage_service_init_settings(struct mail_storage_service_ctx *ctx, { const struct setting_parser_info *user_info; const struct mail_user_settings *user_set; + const struct setting_parser_context *set_parser; const char *error; - void **sets; pool_t temp_pool; if (ctx->conn != NULL) @@ -880,10 +920,10 @@ void mail_storage_service_init_settings(struct mail_storage_service_ctx *ctx, temp_pool = pool_alloconly_create("service all settings", 4096); if (mail_storage_service_read_settings(ctx, input, temp_pool, - &user_info, &error) < 0) + &user_info, &set_parser, + &error) < 0) i_fatal("%s", error); - sets = settings_parser_get_list(ctx->service->set_parser); - user_set = sets[1]; + user_set = settings_parser_get_list(set_parser)[1]; mail_storage_service_first_init(ctx, user_info, user_set); pool_unref(&temp_pool); @@ -923,7 +963,9 @@ void mail_storage_service_deinit(struct mail_storage_service_ctx **_ctx) mail_user_auth_master_conn = NULL; auth_master_deinit(&ctx->conn); } - i_free(ctx); + if (ctx->set_cache != NULL) + master_service_settings_cache_deinit(&ctx->set_cache); + pool_unref(&ctx->pool); module_dir_unload(&modules); mail_storage_deinit(); diff --git a/src/lib-storage/mail-storage-service.h b/src/lib-storage/mail-storage-service.h index a00dc45e30..46a2f9860f 100644 --- a/src/lib-storage/mail-storage-service.h +++ b/src/lib-storage/mail-storage-service.h @@ -5,6 +5,7 @@ struct master_service; struct mail_user; +struct setting_parser_context; enum mail_storage_service_flags { /* Fail if we don't drop root privileges */ @@ -51,6 +52,7 @@ int mail_storage_service_read_settings(struct mail_storage_service_ctx *ctx, const struct mail_storage_service_input *input, pool_t pool, const struct setting_parser_info **user_info_r, + const struct setting_parser_context **parser_r, const char **error_r); /* Read settings and initialize context to use them. Do nothing if service is already initialized. This is mainly necessary when calling _get_auth_conn() diff --git a/src/lib-storage/mail-storage-settings.c b/src/lib-storage/mail-storage-settings.c index a9772c8725..05d91c95c0 100644 --- a/src/lib-storage/mail-storage-settings.c +++ b/src/lib-storage/mail-storage-settings.c @@ -250,14 +250,15 @@ mail_storage_settings_to_index_flags(const struct mail_storage_settings *set) return index_flags; } -const struct dynamic_settings_parser *mail_storage_get_dynamic_parsers(void) +const struct dynamic_settings_parser * +mail_storage_get_dynamic_parsers(pool_t pool) { struct dynamic_settings_parser *parsers; struct mail_storage *const *storages; unsigned int i, j, count; storages = array_get(&mail_storage_classes, &count); - parsers = t_new(struct dynamic_settings_parser, count + 1); + parsers = p_new(pool, struct dynamic_settings_parser, count + 1); parsers[0].name = MAIL_STORAGE_SET_DRIVER_NAME; parsers[0].info = &mail_storage_setting_parser_info; diff --git a/src/lib-storage/mail-storage-settings.h b/src/lib-storage/mail-storage-settings.h index cd207eb7c0..0e6da85c61 100644 --- a/src/lib-storage/mail-storage-settings.h +++ b/src/lib-storage/mail-storage-settings.h @@ -87,6 +87,7 @@ const void *mail_storage_get_driver_settings(struct mail_storage *storage); enum mail_index_open_flags mail_storage_settings_to_index_flags(const struct mail_storage_settings *set); -const struct dynamic_settings_parser *mail_storage_get_dynamic_parsers(void); +const struct dynamic_settings_parser * +mail_storage_get_dynamic_parsers(pool_t pool); #endif diff --git a/src/lmtp/client.c b/src/lmtp/client.c index ad8c808a69..1f5ae544af 100644 --- a/src/lmtp/client.c +++ b/src/lmtp/client.c @@ -149,6 +149,7 @@ static void client_raw_user_create(struct client *client) static void client_read_settings(struct client *client) { struct mail_storage_service_input input; + const struct setting_parser_context *set_parser; const char *error; memset(&input, 0, sizeof(input)); @@ -159,10 +160,11 @@ static void client_read_settings(struct client *client) if (mail_storage_service_read_settings(storage_service, &input, client->pool, &client->user_set_info, - &error) < 0) + &set_parser, &error) < 0) i_fatal("%s", error); - lmtp_settings_dup(client->pool, &client->lmtp_set, &client->set); + lmtp_settings_dup(set_parser, client->pool, + &client->lmtp_set, &client->set); } static void client_generate_session_id(struct client *client) diff --git a/src/lmtp/lmtp-settings.c b/src/lmtp/lmtp-settings.c index 3878e42a29..ad9f3d49a9 100644 --- a/src/lmtp/lmtp-settings.c +++ b/src/lmtp/lmtp-settings.c @@ -81,12 +81,13 @@ const struct setting_parser_info lmtp_setting_parser_info = { .dependencies = lmtp_setting_dependencies }; -void lmtp_settings_dup(pool_t pool, const struct lmtp_settings **lmtp_set_r, +void lmtp_settings_dup(const struct setting_parser_context *set_parser, + pool_t pool, const struct lmtp_settings **lmtp_set_r, const struct lda_settings **lda_set_r) { void **sets; - sets = master_service_settings_get_others(master_service); + sets = settings_parser_get_list(set_parser) + 1; *lda_set_r = settings_dup(&lda_setting_parser_info, sets[1], pool); *lmtp_set_r = settings_dup(&lmtp_setting_parser_info, sets[2], pool); } diff --git a/src/lmtp/lmtp-settings.h b/src/lmtp/lmtp-settings.h index defae30f5c..d57f92ec4d 100644 --- a/src/lmtp/lmtp-settings.h +++ b/src/lmtp/lmtp-settings.h @@ -10,7 +10,8 @@ struct lmtp_settings { extern const struct setting_parser_info lmtp_setting_parser_info; -void lmtp_settings_dup(pool_t pool, const struct lmtp_settings **lmtp_set_r, +void lmtp_settings_dup(const struct setting_parser_context *set_parser, + pool_t pool, const struct lmtp_settings **lmtp_set_r, const struct lda_settings **lda_set_r); #endif diff --git a/src/login-common/login-settings.c b/src/login-common/login-settings.c index 6970b30341..3e27139123 100644 --- a/src/login-common/login-settings.c +++ b/src/login-common/login-settings.c @@ -4,7 +4,9 @@ #include "hostpid.h" #include "var-expand.h" #include "settings-parser.h" +#include "master-service.h" #include "master-service-settings.h" +#include "master-service-settings-cache.h" #include "login-settings.h" #include @@ -94,6 +96,8 @@ static const struct setting_parser_info *default_login_set_roots[] = { const struct setting_parser_info **login_set_roots = default_login_set_roots; +static struct master_service_settings_cache *set_cache; + /* */ static int ssl_settings_check(void *_set ATTR_UNUSED, const char **error_r) { @@ -173,7 +177,7 @@ login_set_var_expand_table(const struct master_service_settings_input *input) } struct login_settings * -login_settings_read(struct master_service *service, pool_t pool, +login_settings_read(pool_t pool, const struct ip_addr *local_ip, const struct ip_addr *remote_ip, const char *local_host, @@ -181,8 +185,10 @@ login_settings_read(struct master_service *service, pool_t pool, { struct master_service_settings_input input; const char *error; + const struct setting_parser_context *parser; + void *const *cache_sets; void **sets; - unsigned int i; + unsigned int i, count; memset(&input, 0, sizeof(input)); input.roots = login_set_roots; @@ -195,15 +201,22 @@ login_settings_read(struct master_service *service, pool_t pool, if (remote_ip != NULL) input.remote_ip = *remote_ip; - /* this function always clears the previous settings pool. since we're - doing per-connection lookups, we always need to duplicate the - settings using another pool. */ - if (master_service_settings_read(service, &input, &error) < 0) + if (set_cache == NULL) { + set_cache = master_service_settings_cache_init(master_service, + input.module, + input.service); + } + + if (master_service_settings_cache_read(set_cache, &input, + &parser, &error) < 0) i_fatal("Error reading configuration: %s", error); - sets = master_service_settings_get_others(service); - for (i = 0; sets[i] != NULL; i++) { - sets[i] = settings_dup(input.roots[i], sets[i], pool); + cache_sets = settings_parser_get_list(parser) + 1; + for (count = 0; cache_sets[count] != NULL; count++) ; + i_assert(input.roots[count] == NULL); + sets = p_new(pool, void *, count + 1); + for (i = 0; i < count; i++) { + sets[i] = settings_dup(input.roots[i], cache_sets[i], pool); if (!settings_check(input.roots[i], pool, sets[i], &error)) { const char *name = input.roots[i]->module_name; i_fatal("settings_check(%s) failed: %s", @@ -217,3 +230,9 @@ login_settings_read(struct master_service *service, pool_t pool, *other_settings_r = sets + 1; return sets[0]; } + +void login_settings_deinit(void) +{ + if (set_cache != NULL) + master_service_settings_cache_deinit(&set_cache); +} diff --git a/src/login-common/login-settings.h b/src/login-common/login-settings.h index b144f8d7fd..0719c49a3d 100644 --- a/src/login-common/login-settings.h +++ b/src/login-common/login-settings.h @@ -1,8 +1,6 @@ #ifndef LOGIN_SETTINGS_H #define LOGIN_SETTINGS_H -struct master_service; - struct login_settings { const char *login_trusted_networks; const char *login_greeting; @@ -37,10 +35,11 @@ extern const struct setting_parser_info **login_set_roots; extern const struct setting_parser_info login_setting_parser_info; struct login_settings * -login_settings_read(struct master_service *service, pool_t pool, +login_settings_read(pool_t pool, const struct ip_addr *local_ip, const struct ip_addr *remote_ip, const char *local_host, void ***other_settings_r); +void login_settings_deinit(void); #endif diff --git a/src/login-common/main.c b/src/login-common/main.c index 8ffdfd2925..ae73873c6a 100644 --- a/src/login-common/main.c +++ b/src/login-common/main.c @@ -109,7 +109,7 @@ client_connected_finish(const struct master_service_connection *conn) } pool = pool_alloconly_create("login client", 5*1024); - set = login_settings_read(master_service, pool, &local_ip, + set = login_settings_read(pool, &local_ip, &conn->remote_ip, NULL, &other_sets); if (!ssl_connections && !conn->ssl) { @@ -318,6 +318,7 @@ static void main_deinit(void) anvil_client_deinit(&anvil); if (auth_client_to != NULL) timeout_remove(&auth_client_to); + login_settings_deinit(); } int main(int argc, char *argv[]) @@ -351,7 +352,7 @@ int main(int argc, char *argv[]) set_pool = pool_alloconly_create("global login settings", 4096); global_login_settings = - login_settings_read(master_service, set_pool, NULL, NULL, NULL, + login_settings_read(set_pool, NULL, NULL, NULL, &global_other_settings); /* main_preinit() needs to know the client limit, which is set by diff --git a/src/login-common/ssl-proxy-openssl.c b/src/login-common/ssl-proxy-openssl.c index 54e415acd9..7bb0247b9a 100644 --- a/src/login-common/ssl-proxy-openssl.c +++ b/src/login-common/ssl-proxy-openssl.c @@ -9,7 +9,6 @@ #include "safe-memset.h" #include "hash.h" #include "llist.h" -#include "master-service.h" #include "master-interface.h" #include "client-common.h" #include "ssl-proxy.h" @@ -1077,7 +1076,7 @@ static void ssl_servername_callback(SSL *ssl, int *al ATTR_UNUSED, host = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); client = proxy->client; - client->set = login_settings_read(master_service, client->pool, + client->set = login_settings_read(client->pool, &client->local_ip, &client->ip, host, &other_sets); ctx = ssl_server_context_get(client->set); diff --git a/src/master/main.c b/src/master/main.c index 9e94a15c81..b566054fd7 100644 --- a/src/master/main.c +++ b/src/master/main.c @@ -295,6 +295,7 @@ sig_settings_reload(const siginfo_t *si ATTR_UNUSED, void *context ATTR_UNUSED) { struct master_service_settings_input input; + struct master_service_settings_output output; const struct master_settings *set; void **sets; struct service_list *new_services; @@ -319,7 +320,8 @@ sig_settings_reload(const siginfo_t *si ATTR_UNUSED, input.roots = set_roots; input.module = MASTER_SERVICE_NAME; input.config_path = services_get_config_socket_path(services); - if (master_service_settings_read(master_service, &input, &error) < 0) { + if (master_service_settings_read(master_service, &input, + &output, &error) < 0) { i_error("Error reading configuration: %s", error); return; }