dovecot-2.2: lib-auth: auth_master_user_list_*() no longer reads...

dovecot at dovecot.org dovecot at dovecot.org
Fri Jul 12 02:26:55 EEST 2013


details:   http://hg.dovecot.org/dovecot-2.2/rev/328bc770af54
changeset: 16610:328bc770af54
user:      Timo Sirainen <tss at iki.fi>
date:      Fri Jul 12 02:26:44 2013 +0300
description:
lib-auth: auth_master_user_list_*() no longer reads the entire user list into memory.

diffstat:

 src/lib-auth/auth-master.c |  100 +++++++++++++++++++++++++-------------------
 src/lib-auth/auth-master.h |    1 -
 2 files changed, 57 insertions(+), 44 deletions(-)

diffs (229 lines):

diff -r c0b0f46ff581 -r 328bc770af54 src/lib-auth/auth-master.c
--- a/src/lib-auth/auth-master.c	Fri Jul 12 02:17:31 2013 +0300
+++ b/src/lib-auth/auth-master.c	Fri Jul 12 02:26:44 2013 +0300
@@ -31,7 +31,7 @@
 	enum auth_master_flags flags;
 
 	int fd;
-	struct ioloop *ioloop;
+	struct ioloop *ioloop, *prev_ioloop;
 	struct io *io;
 	struct istream *input;
 	struct ostream *output;
@@ -61,10 +61,8 @@
 
 struct auth_master_user_list_ctx {
 	struct auth_master_connection *conn;
-	pool_t pool;
-	ARRAY_TYPE(const_string) users;
-	const char *const *user_strings;
-	unsigned int idx, user_count;
+	string_t *username;
+	bool finished;
 	bool failed;
 };
 
@@ -338,6 +336,7 @@
 	if (conn->to != NULL)
 		timeout_remove(&conn->to);
 
+	conn->prev_ioloop = current_ioloop;
 	conn->ioloop = io_loop_create();
 	conn->input = i_stream_create_fd(conn->fd, MAX_INBUF_SIZE, FALSE);
 	conn->output = o_stream_create_fd(conn->fd, MAX_OUTBUF_SIZE, FALSE);
@@ -347,11 +346,10 @@
 	lib_signals_reset_ioloop();
 }
 
-static void auth_master_unset_io(struct auth_master_connection *conn,
-				 struct ioloop *prev_ioloop)
+static void auth_master_unset_io(struct auth_master_connection *conn)
 {
-	if (prev_ioloop != NULL) {
-		io_loop_set_current(prev_ioloop);
+	if (conn->prev_ioloop != NULL) {
+		io_loop_set_current(conn->prev_ioloop);
 		lib_signals_reset_ioloop();
 	}
 	io_loop_set_current(conn->ioloop);
@@ -363,7 +361,7 @@
 	io_loop_destroy(&conn->ioloop);
 
 	if ((conn->flags & AUTH_MASTER_FLAG_NO_IDLE_TIMEOUT) == 0) {
-		if (prev_ioloop == NULL)
+		if (conn->prev_ioloop == NULL)
 			auth_connection_close(conn);
 		else {
 			conn->to = timeout_add(1000*AUTH_MASTER_IDLE_SECS,
@@ -385,18 +383,15 @@
 	return TRUE;
 }
 
-static int auth_master_run_cmd(struct auth_master_connection *conn,
-			       const char *cmd)
+static int auth_master_run_cmd_pre(struct auth_master_connection *conn,
+				   const char *cmd)
 {
-	struct ioloop *prev_ioloop;
 	const char *str;
 
 	if (conn->fd == -1) {
 		if (auth_master_connect(conn) < 0)
 			return -1;
 	}
-
-	prev_ioloop = current_ioloop;
 	auth_master_set_io(conn);
 
 	o_stream_cork(conn->output);
@@ -412,12 +407,16 @@
 
 	if (o_stream_nfinish(conn->output) < 0) {
 		i_error("write(auth socket) failed: %m");
-		conn->aborted = TRUE;
-	} else {
-		io_loop_run(conn->ioloop);
+		auth_master_unset_io(conn);
+		auth_connection_close(conn);
+		return -1;
 	}
+	return 0;
+}
 
-	auth_master_unset_io(conn, prev_ioloop);
+static int auth_master_run_cmd_post(struct auth_master_connection *conn)
+{
+	auth_master_unset_io(conn);
 	if (conn->aborted) {
 		conn->aborted = FALSE;
 		auth_connection_close(conn);
@@ -426,6 +425,15 @@
 	return 0;
 }
 
+static int auth_master_run_cmd(struct auth_master_connection *conn,
+			       const char *cmd)
+{
+	if (auth_master_run_cmd_pre(conn, cmd) < 0)
+		return -1;
+	io_loop_run(conn->ioloop);
+	return auth_master_run_cmd_post(conn);
+}
+
 static unsigned int
 auth_master_next_request_id(struct auth_master_connection *conn)
 {
@@ -617,26 +625,26 @@
 			      void *context)
 {
 	struct auth_master_user_list_ctx *ctx = context;
-	const char *user;
 
 	timeout_reset(ctx->conn->to);
+	str_truncate(ctx->username, 0);
+	io_loop_stop(ctx->conn->ioloop);
 
 	if (strcmp(cmd, "DONE") == 0) {
-		io_loop_stop(ctx->conn->ioloop);
 		if (args[0] != NULL && strcmp(args[0], "fail") == 0) {
 			i_error("User listing returned failure");
 			ctx->failed = TRUE;
 		}
-		return TRUE;
-	}
-	if (strcmp(cmd, "LIST") == 0 && args[0] != NULL) {
+		ctx->finished = TRUE;
+	} else if (strcmp(cmd, "LIST") == 0 && args[0] != NULL) {
 		/* we'll just read all the users into memory. otherwise we'd
 		   have to use a separate connection for listing and there's
 		   a higher chance of a failure since the connection could be
 		   open to dovecot-auth for a long time. */
-		user = p_strdup(ctx->pool, args[0]);
-		array_append(&ctx->users, &user, 1);
-		return TRUE;
+		str_append(ctx->username, args[0]);
+	} else {
+		i_error("User listing returned invalid input");
+		ctx->failed = TRUE;
 	}
 	return FALSE;
 }
@@ -648,13 +656,10 @@
 {
 	struct auth_master_user_list_ctx *ctx;
 	string_t *str;
-	pool_t pool;
 
-	pool = pool_alloconly_create("auth master user list", 10240);
-	ctx = p_new(pool, struct auth_master_user_list_ctx, 1);
-	ctx->pool = pool;
+	ctx = i_new(struct auth_master_user_list_ctx, 1);
 	ctx->conn = conn;
-	i_array_init(&ctx->users, 128);
+	ctx->username = str_new(default_pool, 128);
 
 	conn->reply_callback = auth_user_list_reply_callback;
 	conn->reply_context = ctx;
@@ -669,23 +674,31 @@
 	str_append_c(str, '\n');
 
 	conn->prefix = "userdb list";
-	if (auth_master_run_cmd(conn, str_c(str)) < 0)
+
+	if (auth_master_run_cmd_pre(conn, str_c(str)) < 0)
 		ctx->failed = TRUE;
-	ctx->user_strings = array_get(&ctx->users, &ctx->user_count);
 	conn->prefix = DEFAULT_USERDB_LOOKUP_PREFIX;
 	return ctx;
 }
 
 const char *auth_master_user_list_next(struct auth_master_user_list_ctx *ctx)
 {
-	if (ctx->idx == ctx->user_count)
+	const char *line;
+
+	/* try to read already buffered input */
+	line = i_stream_next_line(ctx->conn->input);
+	if (line != NULL) {
+		T_BEGIN {
+			auth_handle_line(ctx->conn, line);
+		} T_END;
+	} else if (!ctx->failed) {
+		/* wait for more data */
+		io_loop_run(ctx->conn->ioloop);
+	}
+
+	if (ctx->finished || ctx->failed)
 		return NULL;
-	return ctx->user_strings[ctx->idx++];
-}
-
-unsigned int auth_master_user_list_count(struct auth_master_user_list_ctx *ctx)
-{
-	return ctx->user_count;
+	return str_c(ctx->username);
 }
 
 int auth_master_user_list_deinit(struct auth_master_user_list_ctx **_ctx)
@@ -694,7 +707,8 @@
 	int ret = ctx->failed ? -1 : 0;
 
 	*_ctx = NULL;
-	array_free(&ctx->users);
-	pool_unref(&ctx->pool);
+	auth_master_run_cmd_post(ctx->conn);
+	str_free(&ctx->username);
+	i_free(ctx);
 	return ret;
 }
diff -r c0b0f46ff581 -r 328bc770af54 src/lib-auth/auth-master.h
--- a/src/lib-auth/auth-master.h	Fri Jul 12 02:17:31 2013 +0300
+++ b/src/lib-auth/auth-master.h	Fri Jul 12 02:26:44 2013 +0300
@@ -59,7 +59,6 @@
 			   const char *user_mask,
 			   const struct auth_user_info *info) ATTR_NULL(3);
 const char *auth_master_user_list_next(struct auth_master_user_list_ctx *ctx);
-unsigned int auth_master_user_list_count(struct auth_master_user_list_ctx *ctx);
 /* Returns -1 if anything failed, 0 if ok */
 int auth_master_user_list_deinit(struct auth_master_user_list_ctx **ctx);
 


More information about the dovecot-cvs mailing list