Mercurial > dovecot > core-2.2
changeset 16610:328bc770af54
lib-auth: auth_master_user_list_*() no longer reads the entire user list into memory.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Fri, 12 Jul 2013 02:26:44 +0300 |
parents | c0b0f46ff581 |
children | 86275093e7b3 |
files | src/lib-auth/auth-master.c src/lib-auth/auth-master.h |
diffstat | 2 files changed, 57 insertions(+), 44 deletions(-) [+] |
line wrap: on
line diff
--- 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; }
--- 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);