diff options
Diffstat (limited to '')
-rw-r--r-- | src/ipc/ipc-group.c | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/src/ipc/ipc-group.c b/src/ipc/ipc-group.c new file mode 100644 index 0000000..9451419 --- /dev/null +++ b/src/ipc/ipc-group.c @@ -0,0 +1,166 @@ +/* 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); +} |