changeset 4393:9928ebb54719 HEAD

Instead of passing URIs directly to dictionary server, it now accepts only named dictionaries which are configured in config file. SIGHUPing master now restarts dict server.
author Timo Sirainen <tss@iki.fi>
date Sat, 17 Jun 2006 15:24:59 +0300
parents ed8e49b0a4ae
children 0462137fa4ce
files dovecot-example.conf src/dict/dict-server.c src/lib-dict/dict-client.h src/master/dict-process.c src/master/dict-process.h src/master/log.c src/master/log.h src/master/main.c src/master/master-settings.c src/master/master-settings.h
diffstat 10 files changed, 128 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/dovecot-example.conf	Sat Jun 17 15:21:21 2006 +0300
+++ b/dovecot-example.conf	Sat Jun 17 15:24:59 2006 +0300
@@ -939,6 +939,20 @@
 #}
 
 ##
+## Dictionary server settings
+##
+
+# Dictionary can be used by some plugins to store key=value lists.
+# Currently this is only used by dict quota backend. The dictionary can be
+# used either directly or though a dictionary server. The following dict block
+# maps dictionary names to URIs when the server is used. These can then be
+# referenced using URIs in format "proxy:<name>".
+
+dict {
+  #quota = mysql:/etc/dovecot-dict-quota.conf 
+}
+
+##
 ## Plugin settings
 ##
 
--- a/src/dict/dict-server.c	Sat Jun 17 15:21:21 2006 +0300
+++ b/src/dict/dict-server.c	Sat Jun 17 15:24:59 2006 +0300
@@ -23,7 +23,7 @@
 	struct dict_server *server;
 
 	char *username;
-	char *uri;
+	char *name, *uri;
 	struct dict *dict;
 
 	int fd;
@@ -271,7 +271,7 @@
 static int dict_client_parse_handshake(struct dict_client_connection *conn,
 				       const char *line)
 {
-	const char *username;
+	const char *username, *name;
 
 	if (*line++ != DICT_PROTOCOL_CMD_HELLO)
 		return -1;
@@ -296,13 +296,37 @@
 
 	conn->username = i_strdup_until(username, line - 1);
 
-	/* the rest is dict URI */
-	conn->uri = i_strdup(line);
+	/* the rest is dict name. since we're looking it with getenv(),
+	   disallow all funny characters that might confuse it, just in case. */
+	name = line;
+	while (*line > ' ' && *line != '=') line++;
+
+	if (*line != '\0')
+		return -1;
+
+	conn->name = i_strdup(name);
+	return 0;
+}
+
+static int dict_client_dict_init(struct dict_client_connection *conn)
+{
+	const char *uri;
+
+	uri = getenv(t_strconcat("DICT_", conn->name, NULL));
+	if (uri == NULL) {
+		i_error("dict client: Unconfigured dictionary name '%s'",
+			conn->name);
+		return -1;
+	}
+
+	conn->uri = i_strdup(uri);
 	conn->dict = dict_cache_get(conn->server->cache, conn->uri,
 				    conn->username);
-	if (conn->dict == NULL)
+	if (conn->dict == NULL) {
+		/* dictionary initialization failed */
+		i_error("Failed to initialize dictionary '%s'", conn->name);
 		return -1;
-
+	}
 	return 0;
 }
 
@@ -322,7 +346,7 @@
 		return;
 	case -2:
 		/* buffer full */
-		i_error("BUG: Dict client sent us more than %d bytes",
+		i_error("dict client: Sent us more than %d bytes",
 			(int)DICT_CLIENT_MAX_LINE_LENGTH);
 		dict_client_connection_deinit(conn);
 		return;
@@ -334,6 +358,11 @@
 			return;
 
 		if (dict_client_parse_handshake(conn, line) < 0) {
+			i_error("dict client: Broken handshake");
+			dict_client_connection_deinit(conn);
+			return;
+		}
+		if (dict_client_dict_init(conn)) {
 			dict_client_connection_deinit(conn);
 			return;
 		}
@@ -376,6 +405,7 @@
 
 	if (conn->dict != NULL)
 		dict_cache_unref(conn->server->cache, conn->uri);
+	i_free(conn->name);
 	i_free(conn->uri);
 	i_free(conn->username);
 	i_free(conn);
--- a/src/lib-dict/dict-client.h	Sat Jun 17 15:21:21 2006 +0300
+++ b/src/lib-dict/dict-client.h	Sat Jun 17 15:24:59 2006 +0300
@@ -9,7 +9,7 @@
 #define DICT_CLIENT_MAX_LINE_LENGTH (64*1024)
 
 enum {
-        /* <major-version> <minor-version> <user> <dict uri> */
+        /* <major-version> <minor-version> <user> <dict name> */
 	DICT_PROTOCOL_CMD_HELLO = 'H',
 
 	DICT_PROTOCOL_CMD_LOOKUP = 'L', /* <key> */
--- a/src/master/dict-process.c	Sat Jun 17 15:21:21 2006 +0300
+++ b/src/master/dict-process.c	Sat Jun 17 15:24:59 2006 +0300
@@ -1,6 +1,7 @@
 /* Copyright (C) 2006 Timo Sirainen */
 
 #include "common.h"
+#include "array.h"
 #include "ioloop.h"
 #include "network.h"
 #include "fd-close-on-exec.h"
@@ -17,6 +18,8 @@
 struct dict_process {
 	char *path;
 	int fd;
+
+	struct log_io *log;
 	struct io *io;
 };
 
@@ -27,8 +30,9 @@
 static int dict_process_start(struct dict_process *process)
 {
 	struct log_io *log;
-	const char *executable;
-	int i, log_fd;
+	const char *executable, *const *dicts;
+	unsigned int i, count;
+	int log_fd;
 	pid_t pid;
 
 	log_fd = log_create_pipe(&log, 0);
@@ -51,6 +55,8 @@
 		log_set_prefix(log, "dict: ");
 		(void)close(log_fd);
 
+		process->log = log;
+		log_ref(process->log);
                 dict_process_unlisten(process);
 		return 0;
 	}
@@ -75,6 +81,11 @@
 	child_process_init_env();
 	env_put(t_strconcat("DICT_LISTEN_FROM_FD=", process->path, NULL));
 
+	dicts = array_get(&settings_root->dicts, &count);
+	i_assert((count % 2) == 0);
+	for (i = 0; i < count; i += 2)
+		env_put(t_strdup_printf("DICT_%s=%s", dicts[i], dicts[i+1]));
+
 	/* make sure we don't leak syslog fd, but do it last so that
 	   any errors above will be logged */
 	closelog();
@@ -89,6 +100,7 @@
 {
 	struct dict_process *process = context;
 
+	i_assert(process->log == NULL);
 	dict_process_start(process);
 }
 
@@ -157,6 +169,8 @@
 void dict_process_deinit(void)
 {
 	dict_process_unlisten(process);
+	if (process->log != NULL)
+		log_unref(process->log);
 	i_free(process->path);
 	i_free(process);
 }
@@ -166,3 +180,11 @@
 	dict_process_deinit();
 	dict_process_init();
 }
+
+void dict_process_kill(void)
+{
+	if (process->log != NULL) {
+		log_unref(process->log);
+		process->log = NULL;
+	}
+}
--- a/src/master/dict-process.h	Sat Jun 17 15:21:21 2006 +0300
+++ b/src/master/dict-process.h	Sat Jun 17 15:24:59 2006 +0300
@@ -4,5 +4,6 @@
 void dict_process_init(void);
 void dict_process_deinit(void);
 void dict_process_restart(void);
+void dict_process_kill(void);
 
 #endif
--- a/src/master/log.c	Sat Jun 17 15:21:21 2006 +0300
+++ b/src/master/log.c	Sat Jun 17 15:24:59 2006 +0300
@@ -10,6 +10,8 @@
 
 struct log_io {
 	struct log_io *prev, *next;
+	int refcount;
+
 	struct io *io;
 	struct istream *stream;
 
@@ -29,7 +31,6 @@
 
 static int log_it(struct log_io *log_io, const char *line, bool continues);
 static void log_read(void *context);
-static void log_io_free(struct log_io *log_io);
 static void log_throttle_timeout(void *context);
 
 static bool log_write_pending(struct log_io *log_io)
@@ -132,7 +133,7 @@
 	if (ret < 0) {
 		if (ret == -1) {
 			/* closed */
-			log_io_free(log_io);
+			log_unref(log_io);
 			return;
 		}
 
@@ -166,6 +167,7 @@
 	fd_close_on_exec(fd[1], TRUE);
 
 	log_io = i_new(struct log_io, 1);
+	log_io->refcount = 1;
 	log_io->stream = i_stream_create_file(fd[0], default_pool, 1024, TRUE);
 	log_io->max_lines_per_sec =
 		max_lines_per_sec != 0 ? max_lines_per_sec : (unsigned int)-1;
@@ -189,11 +191,19 @@
 	log->prefix = i_strdup(prefix);
 }
 
-static void log_io_free(struct log_io *log_io)
+void log_ref(struct log_io *log_io)
+{
+	log_io->refcount++;
+}
+
+static void log_close(struct log_io *log_io)
 {
 	const unsigned char *data;
 	size_t size;
 
+	if (log_io->destroying)
+		return;
+
 	/* if there was something in buffer, write it */
 	log_io->destroying = TRUE;
 	(void)log_write_pending(log_io);
@@ -218,6 +228,17 @@
 	else
 		throttle_count--;
 	i_stream_destroy(&log_io->stream);
+}
+
+void log_unref(struct log_io *log_io)
+{
+	i_assert(log_io->refcount > 0);
+
+	log_close(log_io);
+
+	if (--log_io->refcount > 0)
+		return;
+
 	i_free(log_io->prefix);
 	i_free(log_io);
 }
@@ -255,7 +276,7 @@
 
 	while (log_ios != NULL) {
 		next = log_ios->next;
-		log_io_free(log_ios);
+		log_unref(log_ios);
 		log_ios = next;
 	}
 
--- a/src/master/log.h	Sat Jun 17 15:21:21 2006 +0300
+++ b/src/master/log.h	Sat Jun 17 15:24:59 2006 +0300
@@ -6,6 +6,9 @@
 int log_create_pipe(struct log_io **log_r, unsigned int max_lines_per_sec);
 void log_set_prefix(struct log_io *log, const char *prefix);
 
+void log_ref(struct log_io *log_io);
+void log_unref(struct log_io *log_io);
+
 void log_init(void);
 void log_deinit(void);
 
--- a/src/master/main.c	Sat Jun 17 15:21:21 2006 +0300
+++ b/src/master/main.c	Sat Jun 17 15:24:59 2006 +0300
@@ -136,6 +136,7 @@
 	/* restart auth and login processes */
         login_processes_destroy_all();
         auth_processes_destroy_all();
+        dict_process_kill();
 
 	if (!master_settings_read(configfile, FALSE))
 		i_warning("Invalid configuration, keeping old one");
--- a/src/master/master-settings.c	Sat Jun 17 15:21:21 2006 +0300
+++ b/src/master/master-settings.c	Sat Jun 17 15:24:59 2006 +0300
@@ -30,6 +30,7 @@
 	SETTINGS_TYPE_AUTH_USERDB,
         SETTINGS_TYPE_NAMESPACE,
 	SETTINGS_TYPE_SOCKET,
+	SETTINGS_TYPE_DICT,
 	SETTINGS_TYPE_PLUGIN
 };
 
@@ -1071,6 +1072,13 @@
 		return parse_setting_from_defs(settings_pool,
 					       socket_setting_defs,
 					       ctx->socket, key, value);
+	case SETTINGS_TYPE_DICT:
+		key = p_strdup(settings_pool, key);
+		value = p_strdup(settings_pool, value);
+
+		array_append(&ctx->server->dicts, &key, 1);
+		array_append(&ctx->server->dicts, &value, 1);
+		return NULL;
 	case SETTINGS_TYPE_PLUGIN:
 		key = p_strdup(settings_pool, key);
 		value = p_strdup(settings_pool, value);
@@ -1109,6 +1117,7 @@
 	*server->imap = *imap_defaults;
 	*server->pop3 = *pop3_defaults;
 
+	ARRAY_CREATE(&server->dicts, settings_pool, const char *, 4);
 	ARRAY_CREATE(&server->imap->plugin_envs, settings_pool,
 		     const char *, 8);
 	ARRAY_CREATE(&server->pop3->plugin_envs, settings_pool,
@@ -1257,6 +1266,17 @@
 		return ctx->namespace != NULL;
 	}
 
+	if (strcmp(type, "dict") == 0) {
+		if (ctx->type != SETTINGS_TYPE_ROOT &&
+		    ctx->type != SETTINGS_TYPE_SERVER) {
+			*errormsg = "Plugin section not allowed here";
+			return FALSE;
+		}
+
+		ctx->type = SETTINGS_TYPE_DICT;
+		return TRUE;
+	}
+
 	if (strcmp(type, "plugin") == 0) {
 		if (ctx->type != SETTINGS_TYPE_ROOT &&
 		    ctx->type != SETTINGS_TYPE_SERVER) {
--- a/src/master/master-settings.h	Sat Jun 17 15:21:21 2006 +0300
+++ b/src/master/master-settings.h	Sat Jun 17 15:24:59 2006 +0300
@@ -223,6 +223,8 @@
 	struct auth_settings auth_defaults;
         struct namespace_settings *namespaces;
 
+	array_t ARRAY_DEFINE(dicts, const char *);
+
 	gid_t login_gid;
 };