]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
doveadm: server-connection - Convert to connection API
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Thu, 29 Jul 2021 12:07:21 +0000 (15:07 +0300)
committerAki Tuomi <aki.tuomi@open-xchange.com>
Mon, 17 Jan 2022 11:52:09 +0000 (13:52 +0200)
src/doveadm/doveadm-dsync.c
src/doveadm/doveadm-mail-server.c
src/doveadm/doveadm-server.h
src/doveadm/server-connection.c
src/doveadm/server-connection.h

index 1078a59980e79ec0eeb6dbe138233c975fc45fe3..11553474613d26a57faa11299075124a64f5353a 100644 (file)
@@ -5,6 +5,7 @@
 #include "array.h"
 #include "execv-const.h"
 #include "child-wait.h"
+#include "connection.h"
 #include "istream.h"
 #include "ostream.h"
 #include "iostream-ssl.h"
@@ -918,7 +919,6 @@ dsync_connect_tcp(struct dsync_cmd_context *ctx,
                                    ctx->ctx.set->doveadm_username);
        server->password = p_strdup(ctx->ctx.pool,
                                    ctx->ctx.set->doveadm_password);
-       p_array_init(&server->connections, ctx->ctx.pool, 1);
        p_array_init(&server->queue, ctx->ctx.pool, 1);
 
        prev_ioloop = current_ioloop;
@@ -941,8 +941,7 @@ dsync_connect_tcp(struct dsync_cmd_context *ctx,
                dsync_server_run_command(ctx, conn);
        }
 
-       if (array_count(&server->connections) > 0)
-               server_connection_destroy(&conn);
+       connection_list_deinit(&server->connections);
 
        dsync_cmd_switch_ioloop_to(ctx, prev_ioloop);
        io_loop_destroy(&ioloop);
index 8c535afc37bb3a451c85e242f4bf5ee9010a5c67..348912de0faf2ff31a8986e85d9f4464db20a356 100644 (file)
@@ -5,6 +5,7 @@
 #include "hash.h"
 #include "str.h"
 #include "strescape.h"
+#include "connection.h"
 #include "ioloop.h"
 #include "istream.h"
 #include "master-service.h"
@@ -75,8 +76,6 @@ static struct doveadm_server *doveadm_server_get(const char *name)
                server->hostname = p == NULL ? server->name :
                        p_strdup_until(server_pool, server->name, p);
 
-               p_array_init(&server->connections, server_pool,
-                            doveadm_settings->doveadm_worker_count);
                p_array_init(&server->queue, server_pool,
                             DOVEADM_SERVER_QUEUE_MAX);
                hash_table_insert(servers, dup_name, server);
@@ -86,7 +85,8 @@ static struct doveadm_server *doveadm_server_get(const char *name)
 
 static bool doveadm_server_have_used_connections(struct doveadm_server *server)
 {
-       return array_count(&server->connections) > 0;
+       return server->connections != NULL &&
+               server->connections->connections != NULL;
 }
 
 static void doveadm_mail_server_cmd_free(struct doveadm_mail_server_cmd **_cmd)
@@ -620,8 +620,9 @@ int doveadm_mail_server_user(struct doveadm_mail_cmd_context *ctx,
        server->ip = proxy_set.host_ip;
        server->ssl_flags = proxy_set.ssl_flags;
        server->port = proxy_set.port;
-       if (array_count(&server->connections) <
-           I_MAX(ctx->set->doveadm_worker_count, 1)) {
+       if (server->connections == NULL ||
+           server->connections->connections_count <
+                       I_MAX(ctx->set->doveadm_worker_count, 1)) {
                if (server_connection_create(server, &conn, error_r) < 0) {
                        internal_failure = TRUE;
                        return -1;
@@ -666,13 +667,7 @@ static void doveadm_servers_destroy_all_connections(void)
 
        iter = hash_table_iterate_init(servers);
        while (hash_table_iterate(iter, servers, &key, &server)) {
-               while (array_count(&server->connections) > 0) {
-                       struct server_connection *const *connp, *conn;
-
-                       connp = array_front(&server->connections);
-                       conn = *connp;
-                       server_connection_destroy(&conn);
-               }
+               connection_list_deinit(&server->connections);
                ssl_iostream_context_unref(&server->ssl_ctx);
        }
        hash_table_iterate_deinit(&iter);
index f22603c1d1800ed54fbe1ba7999aa4b0e48d07eb..8aa4d8146f086db4b13c93e0d16573fc706b7815 100644 (file)
@@ -22,7 +22,7 @@ struct doveadm_server {
        enum auth_proxy_ssl_flags ssl_flags;
        struct ssl_iostream_context *ssl_ctx;
 
-       ARRAY(struct server_connection *) connections;
+       struct connection_list *connections;
        ARRAY_TYPE(string) queue;
 };
 
index afdb632e6b5ad2b768b9b182ba3271171b1d72cc..0c8a7099845b7a30c587aab9551886725635e9d1 100644 (file)
@@ -4,8 +4,6 @@
 #include "array.h"
 #include "base64.h"
 #include "connection.h"
-#include "ioloop.h"
-#include "net.h"
 #include "istream.h"
 #include "istream-multiplex.h"
 #include "ostream.h"
 #include "strescape.h"
 #include "iostream-ssl.h"
 #include "master-service.h"
-#include "master-service-settings.h"
-#include "settings-parser.h"
 #include "doveadm.h"
 #include "doveadm-print.h"
 #include "doveadm-util.h"
 #include "doveadm-server.h"
 #include "server-connection.h"
 
-#include <unistd.h>
-
 #define DOVEADM_LOG_CHANNEL_ID 'L'
 
 #define MAX_INBUF_SIZE (1024*32)
@@ -65,10 +59,10 @@ struct server_connection {
 static struct server_connection *printing_conn = NULL;
 static ARRAY(struct doveadm_server *) print_pending_servers = ARRAY_INIT;
 
-static void server_connection_input(struct server_connection *conn);
 static bool server_connection_input_one(struct server_connection *conn);
 static int server_connection_init_ssl(struct server_connection *conn,
                                      const char **error_r);
+static void server_connection_destroy(struct server_connection **_conn);
 
 static void server_set_print_pending(struct doveadm_server *server)
 {
@@ -85,18 +79,11 @@ static void server_set_print_pending(struct doveadm_server *server)
 
 static void server_print_connection_released(struct doveadm_server *server)
 {
-       struct server_connection *const *conns;
-       unsigned int i, count;
-
-       conns = array_get(&server->connections, &count);
-       for (i = 0; i < count; i++) {
-               if (conns[i]->conn.io != NULL)
-                       continue;
+       struct connection *conn;
 
-               conns[i]->conn.io = io_add(conns[i]->conn.fd_in, IO_READ,
-                                          server_connection_input, conns[i]);
-               io_set_pending(conns[i]->conn.io);
-       }
+       conn = server->connections->connections;
+       for (; conn != NULL; conn = conn->next)
+               connection_input_resume(conn);
 }
 
 static void print_connection_released(void)
@@ -335,10 +322,8 @@ static void server_log_disconnect_error(struct server_connection *conn)
 
        error = conn->ssl_iostream == NULL ? NULL :
                ssl_iostream_get_last_error(conn->ssl_iostream);
-       if (error == NULL) {
-               error = conn->conn.input->stream_errno == 0 ? "EOF" :
-                       strerror(conn->conn.input->stream_errno);
-       }
+       if (error == NULL)
+               error = connection_disconnect_reason(&conn->conn);
        i_error("doveadm server disconnected before handshake: %s", error);
 }
 
@@ -365,17 +350,20 @@ static void server_connection_start_multiplex(struct server_connection *conn)
        struct istream *is = conn->conn.input;
        conn->conn.input = i_stream_create_multiplex(is, MAX_INBUF_SIZE);
        i_stream_unref(&is);
-       io_remove(&conn->conn.io);
-       conn->conn.io = io_add_istream(conn->conn.input,
-                                      server_connection_input, conn);
+
        conn->log_input = i_stream_multiplex_add_channel(conn->conn.input,
                                                         DOVEADM_LOG_CHANNEL_ID);
        conn->io_log = io_add_istream(conn->log_input, server_connection_print_log, conn);
        i_stream_set_return_partial_line(conn->log_input, TRUE);
+
+       /* recreate IO using multiplex istream */
+       connection_streams_changed(&conn->conn);
 }
 
-static void server_connection_input(struct server_connection *conn)
+static void server_connection_input(struct connection *_conn)
 {
+       struct server_connection *conn =
+               container_of(_conn, struct server_connection, conn);
        const char *line;
        const char *error;
 
@@ -422,7 +410,7 @@ static void server_connection_input(struct server_connection *conn)
                        }
                        if (!conn->ssl_done &&
                            (conn->server->ssl_flags & AUTH_PROXY_SSL_FLAG_STARTTLS) != 0) {
-                               io_remove(&conn->conn.io);
+                               connection_input_halt(&conn->conn);
                                if (conn->conn.minor_version < DOVEADM_PROTO_MINOR_MIN_STARTTLS) {
                                        i_error("doveadm STARTTLS failed: Server does not support it");
                                        server_connection_destroy(&conn);
@@ -436,8 +424,7 @@ static void server_connection_input(struct server_connection *conn)
                                        return;
                                }
                                conn->ssl_done = TRUE;
-                               conn->conn.io = io_add_istream(conn->conn.input,
-                                       server_connection_input, conn);
+                               connection_input_resume(&conn->conn);
                        }
                        if (server_connection_authenticate(conn) < 0) {
                                server_connection_destroy(&conn);
@@ -555,6 +542,7 @@ static int server_connection_init_ssl(struct server_connection *conn,
                return -1;
        }
 
+       connection_input_halt(&conn->conn);
        if (io_stream_create_ssl_client(conn->server->ssl_ctx,
                                        conn->server->hostname, &ssl_set,
                                        &conn->conn.input, &conn->conn.output,
@@ -569,9 +557,35 @@ static int server_connection_init_ssl(struct server_connection *conn,
                        ssl_iostream_get_last_error(conn->ssl_iostream));
                return -1;
        }
+       connection_input_resume(&conn->conn);
        return 0;
 }
 
+static void server_connection_destroy_conn(struct connection *_conn)
+{
+       struct server_connection *conn =
+               container_of(_conn, struct server_connection, conn);
+       server_connection_destroy(&conn);
+}
+
+static const struct connection_vfuncs doveadm_client_vfuncs = {
+       .input = server_connection_input,
+       .destroy = server_connection_destroy_conn,
+};
+
+static struct connection_settings doveadm_client_set = {
+       /* Note: These service names are reversed compared to how they usually
+          work. Too late to change now without breaking the protocol. */
+       .service_name_in = "doveadm-client",
+       .service_name_out = "doveadm-server",
+       .major_version = DOVEADM_SERVER_PROTOCOL_VERSION_MAJOR,
+       .minor_version = DOVEADM_SERVER_PROTOCOL_VERSION_MINOR,
+       .dont_send_version = TRUE, /* doesn't work with SSL */
+       .input_max_size = MAX_INBUF_SIZE,
+       .output_max_size = SIZE_MAX,
+       .client = TRUE,
+};
+
 int server_connection_create(struct doveadm_server *server,
                             struct server_connection **conn_r,
                             const char **error_r)
@@ -583,6 +597,12 @@ int server_connection_create(struct doveadm_server *server,
        i_assert(server->username != NULL);
        i_assert(server->password != NULL);
 
+       if (server->connections == NULL) {
+               server->connections =
+                       connection_list_init(&doveadm_client_set,
+                                            &doveadm_client_vfuncs);
+       }
+
        pool = pool_alloconly_create("doveadm server connection", 1024*16);
        conn = p_new(pool, struct server_connection, 1);
        conn->pool = pool;
@@ -592,29 +612,20 @@ int server_connection_create(struct doveadm_server *server,
        } else {
                target = server->name;
        }
-       conn->conn.fd_in = doveadm_connect_with_default_port(target,
-               doveadm_settings->doveadm_port);
-       conn->conn.fd_out = conn->conn.fd_out;
+       int fd = doveadm_connect_with_default_port(target,
+                       doveadm_settings->doveadm_port);
+       net_set_nonblock(fd, TRUE);
+       connection_init_client_fd(server->connections, &conn->conn,
+                                 server->hostname, fd, fd);
 
-       net_set_nonblock(conn->conn.fd_in, TRUE);
-       conn->conn.input = i_stream_create_fd(conn->conn.fd_in, MAX_INBUF_SIZE);
-       conn->conn.output = o_stream_create_fd(conn->conn.fd_in, SIZE_MAX);
        o_stream_set_flush_callback(conn->conn.output,
                                    server_connection_output, conn);
-       o_stream_set_no_error_handling(conn->conn.output, TRUE);
-
-       i_stream_set_name(conn->conn.input, server->name);
-       o_stream_set_name(conn->conn.output, server->name);
-
-       array_push_back(&conn->server->connections, &conn);
 
        if (((server->ssl_flags & AUTH_PROXY_SSL_FLAG_STARTTLS) == 0 &&
             server_connection_init_ssl(conn, error_r) < 0)) {
                server_connection_destroy(&conn);
                return -1;
        }
-       conn->conn.io = io_add_istream(conn->conn.input,
-                                      server_connection_input, conn);
 
        conn->state = SERVER_REPLY_STATE_DONE;
        o_stream_nsend_str(conn->conn.output,
@@ -624,30 +635,18 @@ int server_connection_create(struct doveadm_server *server,
        return 0;
 }
 
-void server_connection_destroy(struct server_connection **_conn)
+static void server_connection_destroy(struct server_connection **_conn)
 {
        struct server_connection *conn = *_conn;
-       struct server_connection *const *conns;
        const char *error;
-       unsigned int i, count;
 
        *_conn = NULL;
 
-       conns = array_get(&conn->server->connections, &count);
-       for (i = 0; i < count; i++) {
-               if (conns[i] == conn) {
-                       array_delete(&conn->server->connections, i, 1);
-                       break;
-               }
-       }
-
        if (conn->callback != NULL) {
                error = conn->ssl_iostream == NULL ? NULL :
                        ssl_iostream_get_last_error(conn->ssl_iostream);
-               if (error == NULL) {
-                       error = conn->conn.input->stream_errno == 0 ? "EOF" :
-                               strerror(conn->conn.input->stream_errno);
-               }
+               if (error == NULL)
+                       error = connection_disconnect_reason(&conn->conn);
                struct doveadm_server_reply reply = {
                        .exit_code = SERVER_EXIT_CODE_DISCONNECTED,
                        .error = error,
@@ -657,19 +656,19 @@ void server_connection_destroy(struct server_connection **_conn)
        if (printing_conn == conn)
                print_connection_released();
 
-       i_stream_destroy(&conn->conn.input);
-       o_stream_destroy(&conn->conn.output);
-       i_stream_unref(&conn->cmd_input);
        /* close cmd_output after its parent, so the "." isn't sent */
+       o_stream_close(conn->conn.output);
        o_stream_destroy(&conn->cmd_output);
+
+       i_stream_unref(&conn->cmd_input);
        ssl_iostream_destroy(&conn->ssl_iostream);
        io_remove(&conn->io_log);
-       /* make sure all logs got consumed */
+       /* make sure all logs got consumed before closing the fd */
        if (conn->log_input != NULL)
                server_connection_print_log(conn);
        i_stream_unref(&conn->log_input);
-       io_remove(&conn->conn.io);
-       i_close_fd(&conn->conn.fd_in);
+
+       connection_deinit(&conn->conn);
        pool_unref(&conn->pool);
 }
 
index b119256da2bf17254f88b581003ae44b36f1849f..c6028eac3c635c96d5f2cd304e1f94b0f168ddb7 100644 (file)
@@ -18,7 +18,6 @@ typedef void server_cmd_callback_t(const struct doveadm_server_reply *reply,
 int server_connection_create(struct doveadm_server *server,
                             struct server_connection **conn_r,
                             const char **error_r);
-void server_connection_destroy(struct server_connection **conn);
 
 void server_connection_get_dest(struct server_connection *conn,
                                struct ip_addr *ip_r, in_port_t *port_r);