]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-imap-urlauth: imap-urlauth-connection - Use the connection.h API.
authorStephan Bosch <stephan.bosch@open-xchange.com>
Sun, 31 Jul 2022 22:08:40 +0000 (00:08 +0200)
committeraki.tuomi <aki.tuomi@open-xchange.com>
Fri, 24 Mar 2023 07:14:54 +0000 (07:14 +0000)
src/lib-imap-urlauth/imap-urlauth-connection.c
src/lib-imap-urlauth/imap-urlauth-connection.h

index acf1bef2b24c025fc2fec480400cd01d059760d5..89bcc7b5ce8dc71c520241cec3ae3d30f2953f77 100644 (file)
@@ -14,6 +14,7 @@
 #include "write-full.h"
 #include "array.h"
 #include "aqueue.h"
+#include "connection.h"
 #include "mail-user.h"
 #include "imap-urlauth-fetch.h"
 
@@ -21,6 +22,7 @@
 
 enum imap_urlauth_state {
        IMAP_URLAUTH_STATE_DISCONNECTED = 0,
+       IMAP_URLAUTH_STATE_CONNECTING,
        IMAP_URLAUTH_STATE_AUTHENTICATING,
        IMAP_URLAUTH_STATE_AUTHENTICATED,
        IMAP_URLAUTH_STATE_SELECTING_TARGET,
@@ -54,17 +56,12 @@ struct imap_urlauth_target {
 };
 
 struct imap_urlauth_connection {
-       int refcount;
+       struct connection conn;
        struct event *event;
 
        char *path, *service, *session_id;
        struct mail_user *user;
 
-       int fd;
-       struct istream *input;
-       struct ostream *output;
-       struct io *io;
-
        struct timeout *to_reconnect, *to_idle, *to_response;
        time_t last_reconnect;
        unsigned int reconnect_attempts;
@@ -88,10 +85,15 @@ struct imap_urlauth_connection {
 
 #define IMAP_URLAUTH_RESPONSE_TIMEOUT_MSECS 2*60*1000
 
-#define IMAP_URLAUTH_HANDSHAKE "VERSION\timap-urlauth\t2\t0\n"
-
 #define IMAP_URLAUTH_MAX_INLINE_LITERAL_SIZE (1024*32)
 
+static struct connection_list *imap_urlauth_connections = NULL;
+
+static void imap_urlauth_connection_connected(struct connection *_conn,
+                                             bool success);
+static void imap_urlauth_connection_input(struct connection *_conn);
+static void imap_urlauth_connection_destroy(struct connection *_conn);
+
 static void
 imap_urlauth_connection_disconnect(struct imap_urlauth_connection *conn,
                                   const char *reason);
@@ -107,6 +109,22 @@ imap_urlauth_connection_timeout_abort(struct imap_urlauth_connection *conn);
 static void
 imap_urlauth_connection_fail(struct imap_urlauth_connection *conn);
 
+static const struct connection_vfuncs imap_urlauth_connection_vfuncs = {
+       .destroy = imap_urlauth_connection_destroy,
+       .input = imap_urlauth_connection_input,
+       .client_connected = imap_urlauth_connection_connected,
+};
+
+static const struct connection_settings imap_urlauth_connection_set = {
+       .service_name_in = "imap-urlauth",
+       .service_name_out = "imap-urlauth",
+       .major_version = IMAP_URLAUTH_PROTOCOL_MAJOR_VERSION,
+       .minor_version = IMAP_URLAUTH_PROTOCOL_MINOR_VERSION,
+       .input_max_size = SIZE_MAX,
+       .output_max_size = SIZE_MAX,
+       .client = TRUE,
+};
+
 struct imap_urlauth_connection *
 imap_urlauth_connection_init(const char *path, const char *service,
                             struct mail_user *user, const char *session_id,
@@ -114,18 +132,27 @@ imap_urlauth_connection_init(const char *path, const char *service,
 {
        struct imap_urlauth_connection *conn;
 
+       if (imap_urlauth_connections == NULL) {
+               imap_urlauth_connections =
+                       connection_list_init(&imap_urlauth_connection_set,
+                                            &imap_urlauth_connection_vfuncs);
+       }
+
        conn = i_new(struct imap_urlauth_connection, 1);
-       conn->refcount = 1;
        conn->service = i_strdup(service);
        conn->path = i_strdup(path);
        if (session_id != NULL)
                conn->session_id = i_strdup(session_id);
        conn->user = user;
-       conn->fd = -1;
        conn->literal_fd = -1;
        conn->idle_timeout_msecs = idle_timeout_msecs;
+
        conn->event = event_create(user->event);
        event_set_append_log_prefix(conn->event, "imap-urlauth: ");
+
+       conn->conn.event_parent = conn->event;
+       connection_init_client_unix(imap_urlauth_connections,
+                                   &conn->conn, conn->path);
        return conn;
 }
 
@@ -146,8 +173,12 @@ void imap_urlauth_connection_deinit(struct imap_urlauth_connection **_conn)
        i_assert(conn->to_reconnect == NULL);
        i_assert(conn->to_response == NULL);
 
+       connection_deinit(&conn->conn);
        event_unref(&conn->event);
        i_free(conn);
+
+       if (imap_urlauth_connections->connections == NULL)
+               connection_list_deinit(&imap_urlauth_connections);
 }
 
 static void
@@ -204,7 +235,7 @@ imap_urlauth_connection_select_target(struct imap_urlauth_connection *conn)
 
        conn->state = IMAP_URLAUTH_STATE_SELECTING_TARGET;
        cmd = t_strdup_printf("USER\t%s\n", str_tabescape(target->userid));
-       if (o_stream_send_str(conn->output, cmd) < 0) {
+       if (o_stream_send_str(conn->conn.output, cmd) < 0) {
                e_warning(conn->event,
                          "Error sending USER request to imap-urlauth server: %m");
                imap_urlauth_connection_fail(conn);
@@ -249,7 +280,7 @@ imap_urlauth_connection_send_request(struct imap_urlauth_connection *conn)
                conn->state = IMAP_URLAUTH_STATE_UNSELECTING_TARGET;
                imap_urlauth_target_free(conn, conn->targets_head);
 
-               if (o_stream_send_str(conn->output, "END\n") < 0) {
+               if (o_stream_send_str(conn->conn.output, "END\n") < 0) {
                        e_warning(conn->event,
                                  "Error sending END request to imap-urlauth server: %m");
                        imap_urlauth_connection_fail(conn);
@@ -272,7 +303,7 @@ imap_urlauth_connection_send_request(struct imap_urlauth_connection *conn)
        str_append_c(cmd, '\n');
 
        conn->state = IMAP_URLAUTH_STATE_REQUEST_PENDING;
-       if (o_stream_send(conn->output, str_data(cmd), str_len(cmd)) < 0) {
+       if (o_stream_send(conn->conn.output, str_data(cmd), str_len(cmd)) < 0) {
                e_warning(conn->event,
                          "Error sending URL request to imap-urlauth server: %m");
                imap_urlauth_connection_fail(conn);
@@ -560,7 +591,7 @@ imap_urlauth_connection_read_literal_data(struct imap_urlauth_connection *conn)
        size_t size;
 
        /* Read data */
-       data = i_stream_get_data(conn->input, &size);
+       data = i_stream_get_data(conn->conn.input, &size);
        if (size > conn->literal_bytes_left)
                size = conn->literal_bytes_left;
 
@@ -576,7 +607,7 @@ imap_urlauth_connection_read_literal_data(struct imap_urlauth_connection *conn)
                        i_assert(conn->literal_buf != NULL);
                        buffer_append(conn->literal_buf, data, size);
                }
-               i_stream_skip(conn->input, size);
+               i_stream_skip(conn->conn.input, size);
                conn->literal_bytes_left -= size;
        }
 
@@ -585,7 +616,7 @@ imap_urlauth_connection_read_literal_data(struct imap_urlauth_connection *conn)
                return 0;
 
        /* Read LF guard */
-       data = i_stream_get_data(conn->input, &size);
+       data = i_stream_get_data(conn->conn.input, &size);
        if (size < 1)
                return 0;
 
@@ -595,7 +626,7 @@ imap_urlauth_connection_read_literal_data(struct imap_urlauth_connection *conn)
                        data[0]);
                return -1;
        }
-       i_stream_skip(conn->input, 1);
+       i_stream_skip(conn->conn.input, 1);
        return 1;
 }
 
@@ -698,6 +729,24 @@ imap_urlauth_connection_read_literal(struct imap_urlauth_connection *conn)
        return 1;
 }
 
+static void imap_urlauth_connection_destroy(struct connection *_conn)
+{
+       struct imap_urlauth_connection *conn =
+               container_of(_conn, struct imap_urlauth_connection, conn);
+
+       switch (_conn->disconnect_reason) {
+       case CONNECTION_DISCONNECT_HANDSHAKE_FAILED:
+               imap_urlauth_connection_disconnect(
+                       conn, "Handshake with imap-urlauth service failed");
+               break;
+       case CONNECTION_DISCONNECT_BUFFER_FULL:
+               i_unreached();
+       default:
+               /* Disconnected */
+               imap_urlauth_connection_reconnect(conn);
+       }
+}
+
 static int imap_urlauth_input_pending(struct imap_urlauth_connection *conn)
 {
        struct imap_urlauth_request *urlreq;
@@ -715,7 +764,7 @@ static int imap_urlauth_input_pending(struct imap_urlauth_connection *conn)
 
        /* "OK"[<metadata-items>]"\t"<literal-size>"\n" or
           "NO"["\terror="<error>]"\n" */
-       if ((response = i_stream_next_line(conn->input)) == NULL)
+       if ((response = i_stream_next_line(conn->conn.input)) == NULL)
                return 0;
        imap_urlauth_stop_response_timeout(conn);
 
@@ -777,9 +826,10 @@ static int imap_urlauth_authenticate(struct imap_urlauth_connection *conn)
 {
        string_t *str;
 
+       conn->state = IMAP_URLAUTH_STATE_AUTHENTICATING;
+
        str = t_str_new(128);
-       str_printfa(str, IMAP_URLAUTH_HANDSHAKE"AUTH\t%s\t%s\t",
-               conn->service, my_pid);
+        str_printfa(str, "AUTH\t%s\t%s\t", conn->service, my_pid);
        str_append_tabescaped(str, conn->user->username);
        str_append_c(str, '\t');
        if (conn->session_id != NULL)
@@ -787,12 +837,13 @@ static int imap_urlauth_authenticate(struct imap_urlauth_connection *conn)
        str_append_c(str, '\t');
        str_append_tabescaped(str, conn->user->auth_token);
        str_append_c(str, '\n');
-       if (o_stream_send(conn->output, str_data(str), str_len(str)) < 0) {
+       if (o_stream_send(conn->conn.output, str_data(str), str_len(str)) < 0) {
                e_warning(conn->event,
                          "Error sending handshake to imap-urlauth server: %m");
                imap_urlauth_connection_abort(conn, NULL);
                return -1;
        }
+
        return 0;
 }
 
@@ -802,9 +853,11 @@ static int imap_urlauth_input_next(struct imap_urlauth_connection *conn)
        int ret;
 
        switch (conn->state) {
+       case IMAP_URLAUTH_STATE_CONNECTING:
+               break;
        case IMAP_URLAUTH_STATE_AUTHENTICATING:
        case IMAP_URLAUTH_STATE_UNSELECTING_TARGET:
-               if ((response = i_stream_next_line(conn->input)) == NULL)
+               if ((response = i_stream_next_line(conn->conn.input)) == NULL)
                        return 0;
                imap_urlauth_stop_response_timeout(conn);
 
@@ -836,7 +889,7 @@ static int imap_urlauth_input_next(struct imap_urlauth_connection *conn)
                imap_urlauth_connection_select_target(conn);
                return 0;
        case IMAP_URLAUTH_STATE_SELECTING_TARGET:
-               if ((response = i_stream_next_line(conn->input)) == NULL)
+               if ((response = i_stream_next_line(conn->conn.input)) == NULL)
                        return 0;
                imap_urlauth_stop_response_timeout(conn);
 
@@ -870,7 +923,7 @@ static int imap_urlauth_input_next(struct imap_urlauth_connection *conn)
        case IMAP_URLAUTH_STATE_AUTHENTICATED:
        case IMAP_URLAUTH_STATE_READY:
        case IMAP_URLAUTH_STATE_REQUEST_WAIT:
-               if ((response = i_stream_next_line(conn->input)) == NULL)
+               if ((response = i_stream_next_line(conn->conn.input)) == NULL)
                        return 0;
 
                e_error(conn->event,
@@ -888,18 +941,21 @@ static int imap_urlauth_input_next(struct imap_urlauth_connection *conn)
        i_unreached();
 }
 
-static void imap_urlauth_input(struct imap_urlauth_connection *conn)
+static void imap_urlauth_connection_input(struct connection *_conn)
 {
+       struct imap_urlauth_connection *conn =
+               container_of(_conn, struct imap_urlauth_connection, conn);
+
        i_assert(conn->state != IMAP_URLAUTH_STATE_DISCONNECTED);
 
-       if (conn->input->closed) {
+       if (conn->conn.input->closed) {
                /* Disconnected */
                e_error(conn->event, "Service disconnected unexpectedly");
                imap_urlauth_connection_fail(conn);
                return;
        }
 
-       switch (i_stream_read(conn->input)) {
+       switch (i_stream_read(conn->conn.input)) {
        case -1:
                /* Disconnected */
                e_error(conn->event, "Service disconnected unexpectedly");
@@ -912,21 +968,36 @@ static void imap_urlauth_input(struct imap_urlauth_connection *conn)
                return;
        }
 
-       while (!conn->input->closed) {
+       while (!conn->conn.input->closed) {
                if (imap_urlauth_input_next(conn) <= 0)
                        break;
        }
 }
 
+static void
+imap_urlauth_connection_connected(struct connection *_conn, bool success)
+{
+       struct imap_urlauth_connection *conn =
+               container_of(_conn, struct imap_urlauth_connection, conn);
+
+       /* Cannot get here unless UNIX socket connect() was successful */
+       i_assert(success);
+
+       if (imap_urlauth_authenticate(conn) < 0)
+               return;
+
+       imap_urlauth_start_response_timeout(conn);
+}
+
 static int
 imap_urlauth_connection_do_connect(struct imap_urlauth_connection *conn)
 {
-       int fd;
-
-       if (conn->state != IMAP_URLAUTH_STATE_DISCONNECTED) {
+       if (conn->state >= IMAP_URLAUTH_STATE_AUTHENTICATED) {
                imap_urlauth_connection_send_request(conn);
                return 1;
        }
+       if (conn->state >= IMAP_URLAUTH_STATE_CONNECTING)
+               return 1;
 
        if (conn->user->auth_token == NULL) {
                e_error(conn->event,
@@ -938,27 +1009,17 @@ imap_urlauth_connection_do_connect(struct imap_urlauth_connection *conn)
 
        e_debug(conn->event, "Connecting to service at %s", conn->path);
 
-       i_assert(conn->fd == -1);
-       fd = net_connect_unix(conn->path);
-       if (fd == -1) {
+       timeout_remove(&conn->to_reconnect);
+
+       conn->state = IMAP_URLAUTH_STATE_CONNECTING;
+       imap_urlauth_start_response_timeout(conn);
+
+       if (connection_client_connect(&conn->conn) < 0) {
                e_error(conn->event, "net_connect_unix(%s) failed: %m",
                        conn->path);
                imap_urlauth_connection_abort(conn, NULL);
                return -1;
        }
-
-       timeout_remove(&conn->to_reconnect);
-
-       conn->fd = fd;
-       conn->input = i_stream_create_fd(fd, SIZE_MAX);
-       conn->output = o_stream_create_fd(fd, SIZE_MAX);
-       conn->io = io_add(fd, IO_READ, imap_urlauth_input, conn);
-       conn->state = IMAP_URLAUTH_STATE_AUTHENTICATING;
-
-       if (imap_urlauth_authenticate(conn) < 0)
-               return -1;
-
-       imap_urlauth_start_response_timeout(conn);
        return 0;
 }
 
@@ -971,22 +1032,19 @@ int imap_urlauth_connection_connect(struct imap_urlauth_connection *conn)
        return 0;
 }
 
-static void imap_urlauth_connection_disconnect
-(struct imap_urlauth_connection *conn, const char *reason)
+static void
+imap_urlauth_connection_disconnect(struct imap_urlauth_connection *conn,
+                                  const char *reason)
 {
        conn->state = IMAP_URLAUTH_STATE_DISCONNECTED;
 
-       if (conn->fd != -1) {
+       if (!conn->conn.disconnected) {
                if (reason == NULL)
                        e_debug(conn->event, "Disconnecting from service");
                else
                        e_debug(conn->event, "Disconnected: %s", reason);
 
-               io_remove(&conn->io);
-               i_stream_destroy(&conn->input);
-               o_stream_destroy(&conn->output);
-               net_disconnect(conn->fd);
-               conn->fd = -1;
+               connection_disconnect(&conn->conn);
        }
        conn->reading_literal = FALSE;
 
@@ -1054,6 +1112,6 @@ imap_urlauth_connection_timeout_abort(struct imap_urlauth_connection *conn)
 
 bool imap_urlauth_connection_is_connected(struct imap_urlauth_connection *conn)
 {
-       return (conn->fd != -1 &&
+       return (conn->conn.disconnected &&
                conn->state != IMAP_URLAUTH_STATE_DISCONNECTED);
 }
index b60186a2c74b55305cf87104a91402fa8606c851..f74156490fb433cdd9232fa9e2678bce4882d285 100644 (file)
@@ -1,6 +1,9 @@
 #ifndef IMAP_URLAUTH_CONNECTION_H
 #define IMAP_URLAUTH_CONNECTION_H
 
+#define IMAP_URLAUTH_PROTOCOL_MAJOR_VERSION 2
+#define IMAP_URLAUTH_PROTOCOL_MINOR_VERSION 0
+
 struct imap_urlauth_request;
 struct imap_urlauth_fetch_reply;