bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen#include "lib.h"
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen#include "ioloop.h"
bdd36cfdba3ff66d25570a9ff568d69e1eb543cfTimo Sirainen#include "net.h"
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen#include "istream.h"
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen#include "ostream.h"
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen#include "llist.h"
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen#include "strescape.h"
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen#include "master-service.h"
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen#include "replication-common.h"
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen#include "replicator-connection.h"
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen#include "notify-connection.h"
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen#define MAX_INBUF_SIZE 8192
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen#define CONNECTION_IS_FIFO(conn) \
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen ((conn)->output == NULL)
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainenstruct notify_connection {
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen struct notify_connection *prev, *next;
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen int refcount;
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen int fd;
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen struct io *io;
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen struct istream *input;
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen struct ostream *output;
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen};
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainenstatic struct notify_connection *conns = NULL;
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainenstatic void notify_connection_unref(struct notify_connection *conn);
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainenstatic void notify_connection_destroy(struct notify_connection *conn);
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainenstatic bool notify_input_error(struct notify_connection *conn)
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen{
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen if (CONNECTION_IS_FIFO(conn))
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen return TRUE;
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen notify_connection_destroy(conn);
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen return FALSE;
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen}
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainenvoid notify_connection_sync_callback(bool success, void *context)
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen{
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen struct notify_connection *conn = context;
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend_str(conn->output, success ? "+\n" : "-\n");
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen notify_connection_unref(conn);
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen}
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainenstatic int
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainennotify_input_line(struct notify_connection *conn, const char *line)
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen{
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen const char *const *args;
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen enum replication_priority priority;
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen /* <username> \t <priority> */
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen args = t_strsplit_tabescaped(line);
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen if (str_array_length(args) < 2) {
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen i_error("Client sent invalid input");
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen return -1;
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen }
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen if (replication_priority_parse(args[1], &priority) < 0) {
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen i_error("Client sent invalid priority: %s", args[1]);
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen return -1;
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen }
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen if (priority != REPLICATION_PRIORITY_SYNC)
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen replicator_connection_notify(replicator, args[0], priority);
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen else {
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen conn->refcount++;
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen replicator_connection_notify_sync(replicator, args[0], conn);
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen }
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen return 0;
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen}
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainenstatic void notify_input(struct notify_connection *conn)
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen{
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen const char *line;
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen int ret;
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen switch (i_stream_read(conn->input)) {
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen case -2:
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen /* buffer full */
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen i_error("Client sent too long line");
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen (void)notify_input_error(conn);
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen return;
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen case -1:
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen /* disconnected */
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen notify_connection_destroy(conn);
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen return;
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen }
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen while ((line = i_stream_next_line(conn->input)) != NULL) {
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen T_BEGIN {
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen ret = notify_input_line(conn, line);
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen } T_END;
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen if (ret < 0) {
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen if (!notify_input_error(conn))
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen return;
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen }
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen }
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen}
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainenvoid notify_connection_create(int fd, bool fifo)
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen{
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen struct notify_connection *conn;
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen conn = i_new(struct notify_connection, 1);
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen conn->refcount = 1;
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen conn->fd = fd;
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen conn->io = io_add(fd, IO_READ, notify_input, conn);
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi conn->input = i_stream_create_fd(fd, MAX_INBUF_SIZE);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen if (!fifo) {
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi conn->output = o_stream_create_fd(fd, (size_t)-1);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_set_no_error_handling(conn->output, TRUE);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen }
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen DLLIST_PREPEND(&conns, conn);
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen}
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainenstatic void notify_connection_unref(struct notify_connection *conn)
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen{
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen i_assert(conn->refcount > 0);
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen if (--conn->refcount > 0)
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen return;
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen i_stream_destroy(&conn->input);
be5773cb4d6edae8a5d9f300c3c7375cdd33826eJosef 'Jeff' Sipek o_stream_destroy(&conn->output);
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen i_free(conn);
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen}
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainenstatic void notify_connection_destroy(struct notify_connection *conn)
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen{
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen i_assert(conn->fd != -1);
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen if (!CONNECTION_IS_FIFO(conn))
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen master_service_client_connection_destroyed(master_service);
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen DLLIST_REMOVE(&conns, conn);
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen io_remove(&conn->io);
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen i_stream_close(conn->input);
9a84b90d894a741ae6e090de104d31382a41d0aaJosef 'Jeff' Sipek o_stream_close(conn->output);
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen net_disconnect(conn->fd);
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen conn->fd = -1;
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen notify_connection_unref(conn);
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen}
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainenvoid notify_connections_destroy_all(void)
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen{
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen while (conns != NULL)
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen notify_connection_destroy(conns);
447e086422f1ab7cc16833583ed70a4af7a84bc5Timo Sirainen}