Mercurial > dovecot > core-2.2
view src/lib-master/ipc-client.c @ 22652:09523ad05bef
director: Log whenever HOST-RESET-USERS is used
author | Timo Sirainen <timo.sirainen@dovecot.fi> |
---|---|
date | Sun, 05 Nov 2017 22:53:23 +0200 |
parents | 2e2563132d5f |
children | cb108f786fb4 |
line wrap: on
line source
/* Copyright (c) 2011-2017 Dovecot authors, see the included COPYING file */ #include "lib.h" #include "array.h" #include "ioloop.h" #include "net.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 { 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; struct istream *input; struct ostream *output; ARRAY(struct ipc_client_cmd) cmds; }; static void ipc_client_disconnect(struct ipc_client *client); static void ipc_client_input_line(struct ipc_client *client, const char *line) { const struct ipc_client_cmd *cmds; unsigned int count; enum ipc_client_cmd_state state; cmds = array_get(&client->cmds, &count); if (count == 0) { 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"; ipc_client_disconnect(client); state = IPC_CLIENT_CMD_STATE_ERROR; break; } cmds[0].callback(state, line, cmds[0].context); if (state != IPC_CLIENT_CMD_STATE_REPLY) array_delete(&client->cmds, 0, 1); } 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_t)-1, FALSE); client->output = o_stream_create_fd(client->fd, (size_t)-1, FALSE); o_stream_set_no_error_handling(client->output, TRUE); return 0; } static void ipc_client_disconnect(struct ipc_client *client) { const struct ipc_client_cmd *cmd; if (client->fd == -1) return; array_foreach(&client->cmds, cmd) { cmd->callback(IPC_CLIENT_CMD_STATE_ERROR, "Disconnected", cmd->context); } array_clear(&client->cmds); 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; i_array_init(&client->cmds, 8); return client; } void ipc_client_deinit(struct ipc_client **_client) { struct ipc_client *client = *_client; *_client = NULL; ipc_client_disconnect(client); array_free(&client->cmds); i_free(client->path); i_free(client); } void 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]; if (ipc_client_connect(client) < 0) { callback(IPC_CLIENT_CMD_STATE_ERROR, "ipc connect failed", context); return; } 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)); ipc_cmd = array_append_space(&client->cmds); ipc_cmd->callback = callback; ipc_cmd->context = context; }