src/director/Makefile
src/dns/Makefile
src/indexer/Makefile
-src/ipc/Makefile
src/imap/Makefile
src/imap-hibernate/Makefile
src/imap-login/Makefile
dict \
dns \
indexer \
- ipc \
master \
login-common \
imap-hibernate \
+++ /dev/null
-pkglibexecdir = $(libexecdir)/dovecot
-
-pkglibexec_PROGRAMS = ipc
-
-AM_CPPFLAGS = \
- -I$(top_srcdir)/src/lib \
- -I$(top_srcdir)/src/lib-settings \
- -I$(top_srcdir)/src/lib-master \
- $(BINARY_CFLAGS)
-
-ipc_LDADD = $(LIBDOVECOT) \
- $(BINARY_LDFLAGS)
-ipc_DEPENDENCIES = $(LIBDOVECOT_DEPS)
-
-ipc_SOURCES = \
- client.c \
- main.c \
- ipc-connection.c \
- ipc-group.c \
- ipc-settings.c
-
-noinst_HEADERS = \
- client.h \
- ipc-connection.h \
- ipc-group.h
+++ /dev/null
-/* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
-
-#include "lib.h"
-#include "llist.h"
-#include "ioloop.h"
-#include "istream.h"
-#include "ostream.h"
-#include "master-service.h"
-#include "ipc-group.h"
-#include "ipc-connection.h"
-#include "client.h"
-
-#include <unistd.h>
-
-struct client {
- struct client *prev, *next;
-
- int fd;
- struct io *io;
- struct istream *input;
- struct ostream *output;
-};
-
-static struct client *clients;
-
-static void client_input(struct client *client);
-
-static void
-client_cmd_input(enum ipc_cmd_status status, const char *line, void *context)
-{
- struct client *client = context;
- char chr = '\0';
-
- switch (status) {
- case IPC_CMD_STATUS_REPLY:
- chr = ':';
- break;
- case IPC_CMD_STATUS_OK:
- chr = '+';
- break;
- case IPC_CMD_STATUS_ERROR:
- chr = '-';
- break;
- }
-
- T_BEGIN {
- o_stream_nsend_str(client->output,
- t_strdup_printf("%c%s\n", chr, line));
- } T_END;
-
- if (status != IPC_CMD_STATUS_REPLY && client->io == NULL) {
- client->io = io_add(client->fd, IO_READ, client_input, client);
- client_input(client);
- }
-}
-
-static void client_input(struct client *client)
-{
- struct ipc_group *group;
- struct ipc_connection *conn;
- char *line, *id, *data;
- unsigned int id_num;
- bool ret;
-
- while ((line = i_stream_read_next_line(client->input)) != NULL) {
- /* <ipc name> *|<id> <command> */
- id = strchr(line, '\t');
- if (id == NULL)
- data = NULL;
- else {
- *id++ = '\0';
- data = strchr(id, '\t');
- }
- if (data == NULL || data[1] == '\0') {
- o_stream_nsend_str(client->output, "-Invalid input\n");
- continue;
- }
- *data++ = '\0';
-
- group = ipc_group_lookup_name(line);
-
- ret = FALSE;
- if (strcmp(id, "*") == 0) {
- /* send to everyone */
- if (group == NULL) {
- client_cmd_input(IPC_CMD_STATUS_OK, "", client);
- } else {
- ret = ipc_group_cmd(group, data,
- client_cmd_input, client);
- }
- } else if (str_to_uint(id, &id_num) < 0) {
- o_stream_nsend_str(client->output,
- t_strdup_printf("-Invalid IPC connection id: %s\n", id));
- continue;
- } else if (group == NULL) {
- o_stream_nsend_str(client->output,
- t_strdup_printf("-Unknown IPC group: %s\n", line));
- } else if ((conn = ipc_connection_lookup_id(group, id_num)) == NULL) {
- o_stream_nsend_str(client->output,
- t_strdup_printf("-Unknown IPC connection id: %u\n", id_num));
- continue;
- } else {
- ipc_connection_cmd(conn, data, client_cmd_input, client);
- ret = TRUE;
- }
-
- if (ret) {
- /* we'll handle commands one at a time. stop reading
- input until this command is finished. */
- io_remove(&client->io);
- break;
- }
- }
- if (client->input->eof || client->input->stream_errno != 0)
- client_destroy(&client);
-}
-
-struct client *client_create(int fd)
-{
- struct client *client;
-
- client = i_new(struct client, 1);
- client->fd = fd;
- client->io = io_add(fd, IO_READ, client_input, client);
- client->input = i_stream_create_fd(fd, SIZE_MAX);
- client->output = o_stream_create_fd(fd, SIZE_MAX);
- o_stream_set_no_error_handling(client->output, TRUE);
-
- DLLIST_PREPEND(&clients, client);
- return client;
-}
-
-void client_destroy(struct client **_client)
-{
- struct client *client = *_client;
-
- *_client = NULL;
-
- DLLIST_REMOVE(&clients, client);
- io_remove(&client->io);
- i_stream_destroy(&client->input);
- o_stream_destroy(&client->output);
- if (close(client->fd) < 0)
- i_error("close(client) failed: %m");
- i_free(client);
-
- master_service_client_connection_destroyed(master_service);
-}
-
-void clients_destroy_all(void)
-{
- while (clients != NULL) {
- struct client *client = clients;
-
- client_destroy(&client);
- }
-}
+++ /dev/null
-#ifndef CLIENT_H
-#define CLIENT_H
-
-struct client *client_create(int fd);
-void client_destroy(struct client **client);
-
-void clients_destroy_all(void);
-
-#endif
+++ /dev/null
-/* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
-
-#include "lib.h"
-#include "array.h"
-#include "ioloop.h"
-#include "istream.h"
-#include "ostream.h"
-#include "llist.h"
-#include "strescape.h"
-#include "master-service.h"
-#include "ipc-group.h"
-#include "ipc-connection.h"
-
-#include <unistd.h>
-
-#define IPC_SERVER_PROTOCOL_MAJOR_VERSION 1
-#define IPC_SERVER_PROTOCOL_MINOR_VERSION 0
-
-#define IPC_SERVER_HANDSHAKE "VERSION\tipc-proxy\t1\t0\n"
-
-static unsigned int connection_id_counter;
-
-static void ipc_connection_cmd_free(struct ipc_connection_cmd **_cmd,
- const char *reason)
-{
- struct ipc_connection_cmd *cmd = *_cmd;
- struct ipc_connection_cmd **cmds;
- unsigned int i, count;
-
- *_cmd = NULL;
-
- cmds = array_get_modifiable(&cmd->conn->cmds, &count);
- for (i = 0; i < count; i++) {
- if (cmds[i] == cmd) {
- array_delete(&cmd->conn->cmds, i, 1);
- break;
- }
- }
- if (cmd->callback != NULL) {
- i_assert(reason != NULL);
- cmd->callback(IPC_CMD_STATUS_ERROR, reason, cmd->context);
- }
- i_free(cmd);
-}
-
-static struct ipc_connection_cmd *
-ipc_connection_cmd_find(struct ipc_connection *conn, unsigned int tag)
-{
- struct ipc_connection_cmd *cmd;
-
- array_foreach_elem(&conn->cmds, cmd) {
- if (cmd->tag == tag)
- return cmd;
- }
- return NULL;
-}
-
-static int
-ipc_connection_input_line(struct ipc_connection *conn, char *line)
-{
- struct ipc_connection_cmd *cmd;
- unsigned int tag;
- enum ipc_cmd_status status;
- char *data;
-
- /* <tag> [:+-]<data> */
- data = strchr(line, '\t');
- if (data == NULL)
- return -1;
-
- *data++ = '\0';
- if (str_to_uint(line, &tag) < 0)
- return -1;
-
- switch (data[0]) {
- case ':':
- status = IPC_CMD_STATUS_REPLY;
- break;
- case '+':
- status = IPC_CMD_STATUS_OK;
- break;
- case '-':
- status = IPC_CMD_STATUS_ERROR;
- break;
- default:
- return -1;
- }
- data++;
-
- cmd = ipc_connection_cmd_find(conn, tag);
- if (cmd == NULL) {
- i_error("IPC server: Input for unexpected command tag %u", tag);
- return 0;
- }
- cmd->callback(status, data, cmd->context);
- if (status != IPC_CMD_STATUS_REPLY) {
- cmd->callback = NULL;
- ipc_connection_cmd_free(&cmd, NULL);
- }
- return 0;
-}
-
-static void ipc_connection_input(struct ipc_connection *conn)
-{
- const char *const *args;
- char *line;
- int ret;
-
- if (i_stream_read(conn->input) < 0) {
- ipc_connection_destroy(&conn, FALSE,
- i_stream_get_disconnect_reason(conn->input));
- return;
- }
-
- if (!conn->version_received) {
- if ((line = i_stream_next_line(conn->input)) == NULL)
- return;
-
- if (!version_string_verify(line, "ipc-server",
- IPC_SERVER_PROTOCOL_MAJOR_VERSION)) {
- ipc_connection_destroy(&conn, TRUE,
- "IPC server not compatible with this server "
- "(mixed old and new binaries?)");
- return;
- }
- conn->version_received = TRUE;
- }
- if (!conn->handshake_received) {
- if ((line = i_stream_next_line(conn->input)) == NULL)
- return;
-
- args = t_strsplit_tabescaped(line);
- if (str_array_length(args) < 3 ||
- strcmp(args[0], "HANDSHAKE") != 0) {
- ipc_connection_destroy(&conn, TRUE,
- "IPC server sent invalid handshake");
- return;
- }
- if (ipc_group_update_name(conn->group, args[1]) < 0) {
- ipc_connection_destroy(&conn, TRUE, t_strdup_printf(
- "IPC server named itself unexpectedly: %s "
- "(existing ones were %s)",
- args[1], conn->group->name));
- return;
- }
- if (str_to_pid(args[2], &conn->pid) < 0) {
- ipc_connection_destroy(&conn, TRUE, t_strdup_printf(
- "IPC server gave broken PID: %s", args[2]));
- return;
- }
- conn->handshake_received = TRUE;
- }
-
- while ((line = i_stream_next_line(conn->input)) != NULL) {
- T_BEGIN {
- ret = ipc_connection_input_line(conn, line);
- } T_END;
- if (ret < 0) {
- ipc_connection_destroy(&conn, TRUE, t_strdup_printf(
- "Invalid input from IPC server '%s': %s",
- conn->group->name, line));
- break;
- }
- }
-}
-
-struct ipc_connection *ipc_connection_create(int listen_fd, int fd)
-{
- struct ipc_connection *conn;
-
- conn = i_new(struct ipc_connection, 1);
- conn->group = ipc_group_lookup_listen_fd(listen_fd);
- if (conn->group == NULL)
- conn->group = ipc_group_alloc(listen_fd);
- conn->id = ++connection_id_counter;
- if (conn->id == 0)
- conn->id = ++connection_id_counter;
- conn->fd = fd;
- conn->io = io_add(fd, IO_READ, ipc_connection_input, conn);
- conn->input = i_stream_create_fd(fd, SIZE_MAX);
- conn->output = o_stream_create_fd(fd, SIZE_MAX);
- o_stream_set_no_error_handling(conn->output, TRUE);
- i_array_init(&conn->cmds, 8);
- o_stream_nsend_str(conn->output, IPC_SERVER_HANDSHAKE);
-
- DLLIST_PREPEND(&conn->group->connections, conn);
- return conn;
-}
-
-void ipc_connection_destroy(struct ipc_connection **_conn,
- bool log_error, const char *error)
-{
- struct ipc_connection *conn = *_conn;
- struct ipc_connection_cmd *const *cmdp, *cmd;
- const char *group_name = conn->group->name != NULL ?
- conn->group->name :
- t_strdup_printf("#%d", conn->group->listen_fd);
-
- *_conn = NULL;
-
- error = t_strdup_printf("IPC: '%s' PID %d server connection: %s",
- group_name, conn->pid, error);
- if (log_error)
- i_error("%s", error);
- DLLIST_REMOVE(&conn->group->connections, conn);
-
- while (array_count(&conn->cmds) > 0) {
- cmdp = array_front(&conn->cmds);
- cmd = *cmdp;
-
- ipc_connection_cmd_free(&cmd, error);
- }
- array_free(&conn->cmds);
-
- io_remove(&conn->io);
- i_stream_destroy(&conn->input);
- o_stream_destroy(&conn->output);
- if (close(conn->fd) < 0)
- i_error("close(ipc connection) failed: %m");
- i_free(conn);
-
- master_service_client_connection_destroyed(master_service);
-}
-
-struct ipc_connection *
-ipc_connection_lookup_id(struct ipc_group *group, unsigned int id)
-{
- struct ipc_connection *conn;
-
- for (conn = group->connections; conn != NULL; conn = conn->next) {
- if (conn->id == id)
- return conn;
- }
- return NULL;
-}
-
-void ipc_connection_cmd(struct ipc_connection *conn, const char *cmd,
- ipc_cmd_callback_t *callback, void *context)
-{
- struct ipc_connection_cmd *ipc_cmd;
-
- ipc_cmd = i_new(struct ipc_connection_cmd, 1);
- ipc_cmd->tag = ++conn->cmd_tag_counter;
- ipc_cmd->conn = conn;
- ipc_cmd->callback = callback;
- ipc_cmd->context = context;
- array_push_back(&conn->cmds, &ipc_cmd);
-
- T_BEGIN {
- o_stream_nsend_str(conn->output,
- t_strdup_printf("%u\t%s\n", ipc_cmd->tag, cmd));
- } T_END;
-}
+++ /dev/null
-#ifndef IPC_CONNECTION_H
-#define IPC_CONNECTION_H
-
-#include "ipc-group.h"
-
-struct ipc_connection_cmd {
- unsigned int tag;
- struct ipc_connection *conn;
-
- ipc_cmd_callback_t *callback;
- void *context;
-};
-
-struct ipc_connection {
- struct ipc_group *group;
- /* prev/next within group */
- struct ipc_connection *prev, *next;
-
- unsigned int id;
- pid_t pid;
-
- int fd;
- struct io *io;
- struct istream *input;
- struct ostream *output;
-
- unsigned int cmd_tag_counter;
-
- /* running commands */
- ARRAY(struct ipc_connection_cmd *) cmds;
-
- bool version_received:1;
- bool handshake_received:1;
-};
-
-struct ipc_connection *ipc_connection_create(int listen_fd, int fd);
-void ipc_connection_destroy(struct ipc_connection **conn,
- bool log_error, const char *error);
-
-struct ipc_connection *
-ipc_connection_lookup_id(struct ipc_group *group, unsigned int id);
-
-void ipc_connection_cmd(struct ipc_connection *conn, const char *cmd,
- ipc_cmd_callback_t *callback, void *context);
-
-#endif
+++ /dev/null
-/* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
-
-#include "lib.h"
-#include "array.h"
-#include "ipc-connection.h"
-#include "ipc-group.h"
-
-struct ipc_group_cmd {
- ipc_cmd_callback_t *callback;
- void *context;
-
- int refcount;
- char *first_error;
-};
-
-static ARRAY(struct ipc_group *) ipc_groups;
-
-struct ipc_group *ipc_group_alloc(int listen_fd)
-{
- struct ipc_group *group;
-
- i_assert(ipc_group_lookup_listen_fd(listen_fd) == NULL);
-
- group = i_new(struct ipc_group, 1);
- group->listen_fd = listen_fd;
- array_push_back(&ipc_groups, &group);
- return group;
-}
-
-void ipc_group_free(struct ipc_group **_group)
-{
- struct ipc_group *const *groups, *group = *_group;
- unsigned int i, count;
-
- i_assert(group->connections == NULL);
-
- *_group = NULL;
- groups = array_get(&ipc_groups, &count);
- for (i = 0; i < count; i++) {
- if (groups[i] == group) {
- array_delete(&ipc_groups, i, 1);
- break;
- }
- }
- i_free(group->name);
- i_free(group);
-}
-
-struct ipc_group *ipc_group_lookup_listen_fd(int listen_fd)
-{
- struct ipc_group *group;
-
- array_foreach_elem(&ipc_groups, group) {
- if (group->listen_fd == listen_fd)
- return group;
- }
- return NULL;
-}
-
-struct ipc_group *ipc_group_lookup_name(const char *name)
-{
- struct ipc_group *group;
-
- array_foreach_elem(&ipc_groups, group) {
- if (group->name != NULL &&
- strcmp(group->name, name) == 0)
- return group;
- }
- return NULL;
-}
-
-int ipc_group_update_name(struct ipc_group *group, const char *name)
-{
- if (group->name == NULL)
- group->name = i_strdup(name);
- else if (strcmp(group->name, name) != 0)
- return -1;
- return 0;
-}
-
-static void ipc_group_cmd_callback(enum ipc_cmd_status status,
- const char *line, void *context)
-{
- struct ipc_group_cmd *group_cmd = context;
-
- i_assert(group_cmd->refcount > 0);
-
- switch (status) {
- case IPC_CMD_STATUS_REPLY:
- group_cmd->callback(IPC_CMD_STATUS_REPLY, line,
- group_cmd->context);
- break;
- case IPC_CMD_STATUS_ERROR:
- if (group_cmd->first_error == NULL)
- group_cmd->first_error = i_strdup(line);
- /* fall through */
- case IPC_CMD_STATUS_OK:
- if (--group_cmd->refcount > 0)
- break;
-
- if (group_cmd->first_error == NULL) {
- group_cmd->callback(IPC_CMD_STATUS_OK, line,
- group_cmd->context);
- } else {
- group_cmd->callback(IPC_CMD_STATUS_ERROR,
- group_cmd->first_error,
- group_cmd->context);
- i_free(group_cmd->first_error);
- }
- i_free(group_cmd);
- break;
- }
-
-}
-
-bool ipc_group_cmd(struct ipc_group *group, const char *cmd,
- ipc_cmd_callback_t *callback, void *context)
-{
- struct ipc_connection *conn, *next;
- struct ipc_group_cmd *group_cmd;
-
- if (group->connections == NULL) {
- callback(IPC_CMD_STATUS_OK, NULL, context);
- return FALSE;
- }
-
- group_cmd = i_new(struct ipc_group_cmd, 1);
- group_cmd->callback = callback;
- group_cmd->context = context;
-
- for (conn = group->connections; conn != NULL; conn = next) {
- next = conn->next;
-
- group_cmd->refcount++;
- ipc_connection_cmd(conn, cmd,
- ipc_group_cmd_callback, group_cmd);
- }
- return TRUE;
-}
-
-void ipc_groups_init(void)
-{
- i_array_init(&ipc_groups, 16);
-}
-
-void ipc_groups_disconnect_all(void)
-{
- struct ipc_group *const *groupp, *group;
-
- while (array_count(&ipc_groups) > 0) {
- groupp = array_front(&ipc_groups);
- group = *groupp;
-
- while ((*groupp)->connections != NULL) {
- struct ipc_connection *conn = (*groupp)->connections;
- ipc_connection_destroy(&conn, FALSE, "Shutting down");
- }
- ipc_group_free(&group);
- }
-}
-
-void ipc_groups_deinit(void)
-{
- ipc_groups_disconnect_all();
- array_free(&ipc_groups);
-}
+++ /dev/null
-#ifndef IPC_GROUP_H
-#define IPC_GROUP_H
-
-enum ipc_cmd_status {
- /* Command received a reply line */
- IPC_CMD_STATUS_REPLY,
- /* Command finished successfully */
- IPC_CMD_STATUS_OK,
- /* Command finished with errors */
- IPC_CMD_STATUS_ERROR
-};
-
-struct ipc_group {
- int listen_fd;
- char *name;
-
- /* connections list also acts as a refcount */
- struct ipc_connection *connections;
-};
-
-/* line is non-NULL only with IPC_CMD_STATUS_REPLY.
- Each line begins with the connection ID and TAB. */
-typedef void ipc_cmd_callback_t(enum ipc_cmd_status status,
- const char *line, void *context);
-
-struct ipc_group *ipc_group_alloc(int listen_fd);
-void ipc_group_free(struct ipc_group **group);
-
-struct ipc_group *ipc_group_lookup_listen_fd(int listen_fd);
-struct ipc_group *ipc_group_lookup_name(const char *name);
-
-/* Returns 0 if name is ok, -1 if name doesn't match the existing one. */
-int ipc_group_update_name(struct ipc_group *group, const char *name);
-
-/* Send a command to all connections in a group. All connections are expected
- to answer something. If there are no connections, callback() is called
- immediately and FALSE is returned. */
-bool ipc_group_cmd(struct ipc_group *group, const char *cmd,
- ipc_cmd_callback_t *callback, void *context);
-
-void ipc_groups_init(void);
-void ipc_groups_deinit(void);
-void ipc_groups_disconnect_all(void);
-
-#endif
+++ /dev/null
-/* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
-
-#include "lib.h"
-#include "buffer.h"
-#include "settings-parser.h"
-#include "service-settings.h"
-
-#include <stddef.h>
-
-/* <settings checks> */
-static struct file_listener_settings ipc_unix_listeners_array[] = {
- { "ipc", 0600, "$default_internal_user", "" },
- { "login/ipc-proxy", 0600, "$default_login_user", "" }
-};
-static struct file_listener_settings *ipc_unix_listeners[] = {
- &ipc_unix_listeners_array[0],
- &ipc_unix_listeners_array[1]
-};
-static buffer_t ipc_unix_listeners_buf = {
- { { ipc_unix_listeners, sizeof(ipc_unix_listeners) } }
-};
-/* </settings checks> */
-
-struct service_settings ipc_service_settings = {
- .name = "ipc",
- .protocol = "",
- .type = "",
- .executable = "ipc",
- .user = "$default_internal_user",
- .group = "",
- .privileged_group = "",
- .extra_groups = "",
- .chroot = "empty",
-
- .drop_priv_before_exec = FALSE,
-
- .process_min_avail = 0,
- .process_limit = 1,
- .client_limit = 0,
- .service_count = 0,
- .idle_kill = 0,
- .vsz_limit = UOFF_T_MAX,
-
- .unix_listeners = { { &ipc_unix_listeners_buf,
- sizeof(ipc_unix_listeners[0]) } },
- .fifo_listeners = ARRAY_INIT,
- .inet_listeners = ARRAY_INIT,
-
- .process_limit_1 = TRUE
-};
+++ /dev/null
-/* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
-
-#include "lib.h"
-#include "restrict-access.h"
-#include "master-service.h"
-#include "master-service-settings.h"
-#include "ipc-group.h"
-#include "ipc-connection.h"
-#include "client.h"
-
-static bool ipc_socket_is_client(const char *name)
-{
- size_t len;
-
- if (strcmp(name, "ipc") == 0)
- return TRUE;
-
- len = strlen(name);
- if (len > 7 && strcmp(name + len - 7, "-client") == 0)
- return TRUE;
- return FALSE;
-}
-
-static void client_connected(struct master_service_connection *conn)
-{
- master_service_client_connection_accept(conn);
-
- if (ipc_socket_is_client(conn->name))
- (void)client_create(conn->fd);
- else
- (void)ipc_connection_create(conn->listen_fd, conn->fd);
-}
-
-static void ipc_die(void)
-{
- clients_destroy_all();
- ipc_groups_disconnect_all();
-}
-
-int main(int argc, char *argv[])
-{
- const enum master_service_flags service_flags =
- /* This process likely won't need to send any stats. It's also
- problematic because it's chrooted to empty directory, so it
- can't reconnect to stats if it gets disconnected. So at
- least for now disable connecting to stats entirely. */
- MASTER_SERVICE_FLAG_DONT_SEND_STATS |
- MASTER_SERVICE_FLAG_UPDATE_PROCTITLE;
- const char *error;
-
- master_service = master_service_init("ipc", service_flags,
- &argc, &argv, "");
- if (master_getopt(master_service) > 0)
- return FATAL_DEFAULT;
- if (master_service_settings_read_simple(master_service,
- NULL, &error) < 0)
- i_fatal("Error reading configuration: %s", error);
- master_service_init_log(master_service);
- master_service_set_die_with_master(master_service, TRUE);
- master_service_set_die_callback(master_service, ipc_die);
-
- restrict_access_by_env(RESTRICT_ACCESS_FLAG_ALLOW_ROOT, NULL);
- restrict_access_allow_coredumps(TRUE);
- ipc_groups_init();
- master_service_init_finish(master_service);
-
- master_service_run(master_service, client_connected);
-
- clients_destroy_all();
- ipc_groups_deinit();
- master_service_deinit(&master_service);
- return 0;
-}
libmaster_la_SOURCES = \
anvil-client.c \
- ipc-client.c \
- ipc-server.c \
master-admin-client.c \
master-auth.c \
master-instance.c \
headers = \
anvil-client.h \
- ipc-client.h \
- ipc-server.h \
master-admin-client.h \
master-auth.h \
master-instance.h \
+++ /dev/null
-/* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
-
-#include "lib.h"
-#include "ioloop.h"
-#include "net.h"
-#include "llist.h"
-#include "istream.h"
-#include "ostream.h"
-#include "hostpid.h"
-#include "master-service.h"
-#include "ipc-client.h"
-
-#include <unistd.h>
-
-struct ipc_client_cmd {
- struct ipc_client_cmd *prev, *next;
-
- ipc_client_callback_t *callback;
- void *context;
-};
-
-struct ipc_client {
- char *path;
- ipc_client_callback_t *callback;
-
- int fd;
- struct io *io;
- struct timeout *to_failed;
- struct istream *input;
- struct ostream *output;
- struct ipc_client_cmd *cmds_head, *cmds_tail;
- unsigned int aborted_cmds_count;
-};
-
-static void ipc_client_disconnect(struct ipc_client *client);
-
-static void ipc_client_input_line(struct ipc_client *client, const char *line)
-{
- struct ipc_client_cmd *cmd = client->cmds_head;
- enum ipc_client_cmd_state state;
- bool disconnect = FALSE;
-
- if (client->aborted_cmds_count > 0) {
- /* the command was already aborted */
- cmd = NULL;
- } else if (cmd == NULL) {
- i_error("IPC proxy sent unexpected input: %s", line);
- return;
- }
-
- switch (*line++) {
- case ':':
- state = IPC_CLIENT_CMD_STATE_REPLY;
- break;
- case '+':
- state = IPC_CLIENT_CMD_STATE_OK;
- break;
- case '-':
- state = IPC_CLIENT_CMD_STATE_ERROR;
- break;
- default:
- i_error("IPC proxy sent invalid input: %s", line);
- line = "Invalid input";
- disconnect = TRUE;
- state = IPC_CLIENT_CMD_STATE_ERROR;
- break;
- }
-
- if (state != IPC_CLIENT_CMD_STATE_REPLY) {
- if (cmd != NULL)
- DLLIST2_REMOVE(&client->cmds_head,
- &client->cmds_tail, cmd);
- else
- client->aborted_cmds_count--;
- }
- if (cmd != NULL)
- cmd->callback(state, line, cmd->context);
- if (state != IPC_CLIENT_CMD_STATE_REPLY)
- i_free(cmd);
- if (disconnect)
- ipc_client_disconnect(client);
-}
-
-static void ipc_client_input(struct ipc_client *client)
-{
- const char *line;
-
- if (i_stream_read(client->input) < 0) {
- ipc_client_disconnect(client);
- return;
- }
- while ((line = i_stream_next_line(client->input)) != NULL) T_BEGIN {
- ipc_client_input_line(client, line);
- } T_END;
-}
-
-static int ipc_client_connect(struct ipc_client *client)
-{
- if (client->fd != -1)
- return 0;
-
- client->fd = net_connect_unix(client->path);
- if (client->fd == -1) {
- i_error("connect(%s) failed: %m", client->path);
- return -1;
- }
-
- client->io = io_add(client->fd, IO_READ, ipc_client_input, client);
- client->input = i_stream_create_fd(client->fd, SIZE_MAX);
- client->output = o_stream_create_fd(client->fd, SIZE_MAX);
- o_stream_set_no_error_handling(client->output, TRUE);
- return 0;
-}
-
-static void ipc_client_abort_commands(struct ipc_client *client,
- const char *reason)
-{
- struct ipc_client_cmd *cmd, *next;
-
- cmd = client->cmds_head;
- client->cmds_head = client->cmds_tail = NULL;
- for (; cmd != NULL; cmd = next) {
- cmd->callback(IPC_CLIENT_CMD_STATE_ERROR, reason, cmd->context);
- next = cmd->next;
- i_free(cmd);
- }
-}
-
-static void ipc_client_disconnect(struct ipc_client *client)
-{
- timeout_remove(&client->to_failed);
- ipc_client_abort_commands(client, "Disconnected");
-
- if (client->fd == -1)
- return;
-
- io_remove(&client->io);
- i_stream_destroy(&client->input);
- o_stream_destroy(&client->output);
- if (close(client->fd) < 0)
- i_error("close(%s) failed: %m", client->path);
- client->fd = -1;
-}
-
-struct ipc_client *
-ipc_client_init(const char *ipc_socket_path)
-{
- struct ipc_client *client;
-
- client = i_new(struct ipc_client, 1);
- client->path = i_strdup(ipc_socket_path);
- client->fd = -1;
- return client;
-}
-
-void ipc_client_deinit(struct ipc_client **_client)
-{
- struct ipc_client *client = *_client;
-
- *_client = NULL;
-
- ipc_client_disconnect(client);
- i_free(client->path);
- i_free(client);
-}
-
-static void ipc_client_cmd_connect_failed(struct ipc_client *client)
-{
- ipc_client_abort_commands(client, "ipc connect failed");
- timeout_remove(&client->to_failed);
-}
-
-struct ipc_client_cmd *
-ipc_client_cmd(struct ipc_client *client, const char *cmd,
- ipc_client_callback_t *callback, void *context)
-{
- struct ipc_client_cmd *ipc_cmd;
- struct const_iovec iov[2];
-
- ipc_cmd = i_new(struct ipc_client_cmd, 1);
- ipc_cmd->callback = callback;
- ipc_cmd->context = context;
- DLLIST2_APPEND(&client->cmds_head, &client->cmds_tail, ipc_cmd);
-
- if (client->to_failed != NULL ||
- ipc_client_connect(client) < 0) {
- /* Delay calling the failure callback. Fail all commands until
- the callback is called. */
- if (client->to_failed == NULL) {
- client->to_failed = timeout_add_short(0,
- ipc_client_cmd_connect_failed, client);
- }
- } else {
- iov[0].iov_base = cmd;
- iov[0].iov_len = strlen(cmd);
- iov[1].iov_base = "\n";
- iov[1].iov_len = 1;
- o_stream_nsendv(client->output, iov, N_ELEMENTS(iov));
- }
- return ipc_cmd;
-}
-
-void ipc_client_cmd_abort(struct ipc_client *client,
- struct ipc_client_cmd **_cmd)
-{
- struct ipc_client_cmd *cmd = *_cmd;
-
- *_cmd = NULL;
- cmd->callback = NULL;
- /* Free the command only if it's the oldest. Free also other such
- commands in case they were aborted earlier. */
- while (client->cmds_head != NULL &&
- client->cmds_head->callback == NULL) {
- struct ipc_client_cmd *head = client->cmds_head;
-
- client->aborted_cmds_count++;
- DLLIST2_REMOVE(&client->cmds_head, &client->cmds_tail, head);
- i_free(head);
- }
-}
+++ /dev/null
-#ifndef IPC_CLIENT_H
-#define IPC_CLIENT_H
-
-enum ipc_client_cmd_state {
- IPC_CLIENT_CMD_STATE_REPLY,
- IPC_CLIENT_CMD_STATE_OK,
- IPC_CLIENT_CMD_STATE_ERROR
-};
-
-typedef void ipc_client_callback_t(enum ipc_client_cmd_state state,
- const char *data, void *context);
-
-struct ipc_client *
-ipc_client_init(const char *ipc_socket_path);
-void ipc_client_deinit(struct ipc_client **client);
-
-struct ipc_client_cmd *
-ipc_client_cmd(struct ipc_client *client, const char *cmd,
- ipc_client_callback_t *callback, void *context)
- ATTR_NULL(4);
-void ipc_client_cmd_abort(struct ipc_client *client,
- struct ipc_client_cmd **cmd);
-
-#endif
+++ /dev/null
-/* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
-
-#include "lib.h"
-#include "ioloop.h"
-#include "net.h"
-#include "istream.h"
-#include "ostream.h"
-#include "hostpid.h"
-#include "master-service.h"
-#include "ipc-server.h"
-
-#include <unistd.h>
-
-#define IPC_SERVER_RECONNECT_MSECS (10*1000)
-#define IPC_SERVER_PROTOCOL_MAJOR_VERSION 1
-#define IPC_SERVER_PROTOCOL_MINOR_VERSION 0
-#define IPC_SERVER_HANDSHAKE "VERSION\tipc-server\t1\t0\nHANDSHAKE\t%s\t%s\n"
-
-struct ipc_cmd {
- struct ipc_server *server;
- unsigned int tag;
-};
-
-struct ipc_server {
- char *name, *path;
- ipc_command_callback_t *callback;
-
- int ipc_cmd_refcount;
-
- int fd;
- struct io *io;
- struct timeout *to;
- struct istream *input;
- struct ostream *output;
-
- bool version_received:1;
-};
-
-static void ipc_server_disconnect(struct ipc_server *server);
-static void ipc_server_connect(struct ipc_server *server);
-
-static void ipc_server_input_line(struct ipc_server *server, char *line)
-{
- struct ipc_cmd *cmd;
- unsigned int tag = 0;
- char *p;
-
- /* tag cmd */
- p = strchr(line, '\t');
- if (p != NULL) {
- *p++ = '\0';
- if (str_to_uint(line, &tag) < 0)
- p = NULL;
- }
- if (p == NULL || *p == '\0') {
- i_error("IPC proxy sent invalid input: %s", line);
- return;
- }
-
- cmd = i_new(struct ipc_cmd, 1);
- cmd->server = server;
- cmd->tag = tag;
-
- server->ipc_cmd_refcount++;
- T_BEGIN {
- server->callback(cmd, p);
- } T_END;
-}
-
-static void ipc_server_input(struct ipc_server *server)
-{
- char *line;
-
- if (i_stream_read(server->input) < 0) {
- ipc_server_disconnect(server);
- ipc_server_connect(server);
- return;
- }
-
- if (!server->version_received) {
- if ((line = i_stream_next_line(server->input)) == NULL)
- return;
-
- if (!version_string_verify(line, "ipc-proxy",
- IPC_SERVER_PROTOCOL_MAJOR_VERSION)) {
- i_error("IPC proxy not compatible with this server "
- "(mixed old and new binaries?)");
- ipc_server_disconnect(server);
- return;
- }
- server->version_received = TRUE;
- }
-
- while ((line = i_stream_next_line(server->input)) != NULL)
- ipc_server_input_line(server, line);
-}
-
-static void ipc_server_connect(struct ipc_server *server)
-{
- i_assert(server->fd == -1);
-
- timeout_remove(&server->to);
-
- server->fd = net_connect_unix(server->path);
- if (server->fd == -1) {
- i_error("connect(%s) failed: %m", server->path);
- server->to = timeout_add(IPC_SERVER_RECONNECT_MSECS,
- ipc_server_connect, server);
- return;
- }
-
- server->io = io_add(server->fd, IO_READ, ipc_server_input, server);
- server->input = i_stream_create_fd(server->fd, SIZE_MAX);
- server->output = o_stream_create_fd(server->fd, SIZE_MAX);
- o_stream_set_no_error_handling(server->output, TRUE);
- o_stream_nsend_str(server->output,
- t_strdup_printf(IPC_SERVER_HANDSHAKE, server->name, my_pid));
- o_stream_cork(server->output);
-}
-
-static void ipc_server_disconnect(struct ipc_server *server)
-{
- if (server->fd == -1)
- return;
-
- io_remove(&server->io);
- i_stream_destroy(&server->input);
- o_stream_destroy(&server->output);
- if (close(server->fd) < 0)
- i_error("close(%s) failed: %m", server->path);
- server->fd = -1;
-}
-
-struct ipc_server *
-ipc_server_init(const char *ipc_socket_path, const char *name,
- ipc_command_callback_t *callback)
-{
- struct ipc_server *server;
-
- server = i_new(struct ipc_server, 1);
- server->name = i_strdup(name);
- server->path = i_strdup(ipc_socket_path);
- server->callback = callback;
- server->fd = -1;
- ipc_server_connect(server);
- return server;
-}
-
-void ipc_server_deinit(struct ipc_server **_server)
-{
- struct ipc_server *server = *_server;
-
- *_server = NULL;
-
- i_assert(server->ipc_cmd_refcount == 0);
-
- ipc_server_disconnect(server);
- timeout_remove(&server->to);
- i_free(server->name);
- i_free(server->path);
- i_free(server);
-}
-
-void ipc_cmd_send(struct ipc_cmd *cmd, const char *data)
-{
- o_stream_nsend_str(cmd->server->output,
- t_strdup_printf("%u\t:%s\n", cmd->tag, data));
-}
-
-static void ipc_cmd_finish(struct ipc_cmd *cmd, const char *line)
-{
- o_stream_nsend_str(cmd->server->output,
- t_strdup_printf("%u\t%s\n", cmd->tag, line));
- o_stream_uncork(cmd->server->output);
-
- i_assert(cmd->server->ipc_cmd_refcount > 0);
- cmd->server->ipc_cmd_refcount--;
- i_free(cmd);
-}
-
-void ipc_cmd_success(struct ipc_cmd **_cmd)
-{
- ipc_cmd_success_reply(_cmd, "");
-}
-
-void ipc_cmd_success_reply(struct ipc_cmd **_cmd, const char *data)
-{
- struct ipc_cmd *cmd = *_cmd;
-
- *_cmd = NULL;
- ipc_cmd_finish(cmd, t_strconcat("+", data, NULL));
-}
-
-void ipc_cmd_fail(struct ipc_cmd **_cmd, const char *errormsg)
-{
- struct ipc_cmd *cmd = *_cmd;
-
- i_assert(errormsg != NULL);
-
- *_cmd = NULL;
- ipc_cmd_finish(cmd, t_strconcat("-", errormsg, NULL));
-}
+++ /dev/null
-#ifndef IPC_SERVER_H
-#define IPC_SERVER_H
-
-struct ipc_cmd;
-
-/* The callback must eventually free the cmd by calling ip_cmd_success/fail().
- line is guaranteed to be non-empty. */
-typedef void ipc_command_callback_t(struct ipc_cmd *cmd, const char *line);
-
-struct ipc_server *
-ipc_server_init(const char *ipc_socket_path, const char *name,
- ipc_command_callback_t *callback);
-void ipc_server_deinit(struct ipc_server **server);
-
-void ipc_cmd_send(struct ipc_cmd *cmd, const char *data);
-void ipc_cmd_success(struct ipc_cmd **cmd);
-void ipc_cmd_success_reply(struct ipc_cmd **cmd, const char *data);
-void ipc_cmd_fail(struct ipc_cmd **cmd, const char *errormsg);
-
-#endif