diff options
Diffstat (limited to 'src/imap-hibernate/imap-master-connection.c')
-rw-r--r-- | src/imap-hibernate/imap-master-connection.c | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/src/imap-hibernate/imap-master-connection.c b/src/imap-hibernate/imap-master-connection.c new file mode 100644 index 0000000..71fa4dd --- /dev/null +++ b/src/imap-hibernate/imap-master-connection.c @@ -0,0 +1,140 @@ +/* Copyright (c) 2015-2018 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "ioloop.h" +#include "connection.h" +#include "imap-master-connection.h" + +#define IMAP_MASTER_CONNECTION_TIMEOUT_MSECS 30000 + +struct imap_master_connection { + struct connection conn; + struct timeout *to; + + imap_master_connection_send_callback_t *send_callback; + imap_master_connection_read_callback_t *read_callback; + void *context; +}; + +static struct connection_list *master_clients; + +static void imap_master_connection_timeout(struct imap_master_connection *conn) +{ + e_error(conn->conn.event, + "Timeout communicating with %s (version %sreceived)", + conn->conn.name, conn->conn.version_received ? "" : "not "); + imap_master_connection_deinit(&conn); +} + +int imap_master_connection_init(const char *path, + imap_master_connection_send_callback_t *send_callback, + imap_master_connection_read_callback_t *read_callback, + void *context, + struct imap_master_connection **conn_r, + const char **error_r) +{ + struct imap_master_connection *conn; + + conn = i_new(struct imap_master_connection, 1); + conn->send_callback = send_callback; + conn->read_callback = read_callback; + conn->context = context; + connection_init_client_unix(master_clients, &conn->conn, path); + if (connection_client_connect(&conn->conn) < 0) { + int ret = errno == EAGAIN ? 0 : -1; + + *error_r = t_strdup_printf( + "net_connect_unix(%s) failed: %m", path); + connection_deinit(&conn->conn); + i_free(conn); + return ret; + } + conn->to = timeout_add(IMAP_MASTER_CONNECTION_TIMEOUT_MSECS, + imap_master_connection_timeout, conn); + *conn_r = conn; + return 1; +} + +static void +imap_master_read_callback(struct imap_master_connection **_conn, + const char *line) +{ + struct imap_master_connection *conn = *_conn; + imap_master_connection_read_callback_t *read_callback = + conn->read_callback; + + *_conn = NULL; + conn->read_callback = NULL; + read_callback(conn->context, line); + /* connection is destroyed now */ +} + +void imap_master_connection_deinit(struct imap_master_connection **_conn) +{ + imap_master_read_callback(_conn, t_strdup_printf( + "-%s", connection_disconnect_reason(&(*_conn)->conn))); +} + +void imap_master_connection_free(struct imap_master_connection **_conn) +{ + struct imap_master_connection *conn = *_conn; + + *_conn = NULL; + + timeout_remove(&conn->to); + connection_deinit(&conn->conn); + i_free(conn); +} + +static void imap_master_client_destroy(struct connection *_conn) +{ + struct imap_master_connection *conn = + (struct imap_master_connection *)_conn; + + imap_master_connection_deinit(&conn); +} + +static int +imap_master_client_input_line(struct connection *_conn, const char *line) +{ + struct imap_master_connection *conn = + (struct imap_master_connection *)_conn; + + if (!_conn->version_received) { + if (connection_input_line_default(_conn, line) < 0) + return -1; + + conn->send_callback(conn->context, _conn->output); + return 1; + } else { + imap_master_read_callback(&conn, line); + /* we're finished now with this connection - disconnect it */ + return -1; + } +} + +static struct connection_settings client_set = { + .service_name_in = "imap-master", + .service_name_out = "imap-master", + .major_version = 1, + .minor_version = 0, + + .input_max_size = SIZE_MAX, + .output_max_size = SIZE_MAX, + .client = TRUE +}; + +static const struct connection_vfuncs client_vfuncs = { + .destroy = imap_master_client_destroy, + .input_line = imap_master_client_input_line +}; + +void imap_master_connections_init(void) +{ + master_clients = connection_list_init(&client_set, &client_vfuncs); +} + +void imap_master_connections_deinit(void) +{ + connection_list_deinit(&master_clients); +} |