ipc-group.c revision bcb4e51a409d94ae670de96afb8483a4f7855294
18daenzerorama/* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
18daenzerorama
18daenzerorama#include "lib.h"
18daenzerorama#include "array.h"
18daenzerorama#include "ipc-connection.h"
18daenzerorama#include "ipc-group.h"
18daenzerorama
18daenzeroramastruct ipc_group_cmd {
18daenzerorama ipc_cmd_callback_t *callback;
18daenzerorama void *context;
18daenzerorama
18daenzerorama int refcount;
18daenzerorama char *first_error;
18daenzerorama};
18daenzerorama
18daenzeroramastatic ARRAY(struct ipc_group *) ipc_groups;
18daenzerorama
18daenzeroramastruct ipc_group *ipc_group_alloc(int listen_fd)
18daenzerorama{
18daenzerorama struct ipc_group *group;
18daenzerorama
18daenzerorama i_assert(ipc_group_lookup_listen_fd(listen_fd) == NULL);
18daenzerorama
18daenzerorama group = i_new(struct ipc_group, 1);
18daenzerorama group->listen_fd = listen_fd;
18daenzerorama array_append(&ipc_groups, &group, 1);
18daenzerorama return group;
18daenzerorama}
18daenzerorama
18daenzeroramavoid ipc_group_free(struct ipc_group **_group)
18daenzerorama{
18daenzerorama struct ipc_group *const *groups, *group = *_group;
18daenzerorama unsigned int i, count;
18daenzerorama
18daenzerorama i_assert(group->connections == NULL);
18daenzerorama
18daenzerorama *_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 *const *groupp;
array_foreach(&ipc_groups, groupp) {
if ((*groupp)->listen_fd == listen_fd)
return *groupp;
}
return NULL;
}
struct ipc_group *ipc_group_lookup_name(const char *name)
{
struct ipc_group *const *groupp;
array_foreach(&ipc_groups, groupp) {
if ((*groupp)->name != NULL &&
strcmp((*groupp)->name, name) == 0)
return *groupp;
}
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_deinit(void)
{
struct ipc_group *const *groupp, *group;
while (array_count(&ipc_groups) > 0) {
groupp = array_idx(&ipc_groups, 0);
group = *groupp;
while ((*groupp)->connections != NULL) {
struct ipc_connection *conn = (*groupp)->connections;
ipc_connection_destroy(&conn, FALSE, "Shutting down");
}
ipc_group_free(&group);
}
array_free(&ipc_groups);
}