#include "llist.h"
#include "istream.h"
#include "ostream.h"
+#include "istream-multiplex.h"
+#include "ostream-multiplex.h"
#include "connection.h"
#include "strescape.h"
#include "master-service.h"
struct anvil_connection {
struct connection conn;
+ char *service;
bool master:1;
bool fifo:1;
};
return 0;
}
+static int
+anvil_connection_handshake(struct anvil_connection *conn,
+ const char *const *args)
+{
+ /* UNIX socket connections contain a handshake. It contains a PID of
+ the connecting process, which is verified with UNIX credentials if
+ they're available. */
+ pid_t pid;
+
+ if (args[0] == NULL) {
+ /* No service/pid. The client doesn't support admin-commands
+ via anvil socket. */
+ return 0;
+ }
+
+ conn->service = i_strdup(args[0]);
+ if (args[1] == NULL || str_to_pid(args[1], &pid) < 0) {
+ e_error(conn->conn.event, "Invalid handshake pid: %s", args[1]);
+ return -1;
+ }
+ if (pid != conn->conn.remote_pid &&
+ conn->conn.remote_pid != (pid_t)-1) {
+ e_error(conn->conn.event,
+ "Handshake PID %ld doesn't match UNIX credentials PID %ld",
+ (long)pid, (long)conn->conn.remote_pid);
+ return -1;
+ }
+
+ /* Switch input and output to use multiplex stream. The main
+ input/output contains the first channel. */
+ struct istream *orig_input = conn->conn.input;
+ conn->conn.input = i_stream_create_multiplex(orig_input, MAX_INBUF_SIZE);
+ i_stream_unref(&orig_input);
+
+ struct ostream *orig_output = conn->conn.output;
+ conn->conn.output = o_stream_create_multiplex(orig_output, SIZE_MAX);
+ o_stream_set_no_error_handling(conn->conn.output, TRUE);
+ o_stream_unref(&orig_output);
+
+ connection_streams_changed(&conn->conn);
+ return 0;
+}
+
static int
anvil_connection_input_line(struct connection *_conn, const char *line)
{
}
args = t_strsplit_tabescaped(line);
+ if (!conn->conn.handshake_received && !conn->fifo) {
+ if (anvil_connection_handshake(conn, args) < 0)
+ return -1;
+ conn->conn.handshake_received = TRUE;
+ return 1;
+ }
+
if (args[0] == NULL) {
i_error("Anvil client sent empty line");
return -1;
connection_deinit(&conn->conn);
o_stream_destroy(&conn->conn.output);
+ i_free(conn->service);
i_free(conn);
if (!fifo)
static void penalty_lookup(struct penalty_context *ctx)
{
-#define ANVIL_HANDSHAKE "VERSION\tanvil\t2\t0\n"
+#define ANVIL_HANDSHAKE "VERSION\tanvil\t2\t0\n\n"
#define ANVIL_CMD ANVIL_HANDSHAKE"PENALTY-DUMP\n"
struct istream *input;
const char *line;
struct doveadm_who_iter *doveadm_who_iter_init(const char *anvil_path)
{
-#define ANVIL_HANDSHAKE "VERSION\tanvil\t2\t0\n"
+#define ANVIL_HANDSHAKE "VERSION\tanvil\t2\t0\n\n"
#define ANVIL_CMD ANVIL_HANDSHAKE"CONNECT-DUMP\n"
struct doveadm_who_iter *iter;
const char *line;
#include "net.h"
#include "istream.h"
#include "ostream.h"
+#include "istream-multiplex.h"
+#include "ostream-multiplex.h"
+#include "hostpid.h"
#include "array.h"
#include "aqueue.h"
+#include "master-service.h"
#include "anvil-client.h"
struct anvil_query {
enum anvil_client_flags flags;
};
-#define ANVIL_HANDSHAKE "VERSION\tanvil\t2\t0\n"
+#define ANVIL_HANDSHAKE "VERSION\tanvil\t2\t0\n%s\t%s\n"
#define ANVIL_INBUF_SIZE 1024
#define ANVIL_RECONNECT_MIN_SECS 5
#define ANVIL_QUERY_TIMEOUT_MSECS (1000*5)
i_free(client);
}
+static void anvil_client_start_multiplex_input(struct anvil_client *client)
+{
+ struct istream *orig_input = client->input;
+ client->input = i_stream_create_multiplex(orig_input, ANVIL_INBUF_SIZE);
+ i_stream_unref(&orig_input);
+}
+
+static void
+anvil_client_start_multiplex_output(struct anvil_client *client)
+{
+ struct ostream *orig_output = client->output;
+ client->output = o_stream_create_multiplex(orig_output, SIZE_MAX);
+ o_stream_set_no_error_handling(client->output, TRUE);
+ o_stream_unref(&orig_output);
+}
+
static void anvil_reconnect(struct anvil_client *client)
{
anvil_client_disconnect(client);
client->input = i_stream_create_fd(fd, ANVIL_INBUF_SIZE);
client->output = o_stream_create_fd(fd, SIZE_MAX);
client->io = io_add(fd, IO_READ, anvil_input, client);
- if (o_stream_send_str(client->output, ANVIL_HANDSHAKE) < 0) {
+ const char *anvil_handshake =
+ t_strdup_printf(ANVIL_HANDSHAKE,
+ master_service_get_name(master_service),
+ my_pid);
+ if (o_stream_send_str(client->output, anvil_handshake) < 0) {
i_error("write(%s) failed: %s", client->path,
o_stream_get_error(client->output));
anvil_reconnect(client);
return -1;
}
+
+ anvil_client_start_multiplex_input(client);
+ anvil_client_start_multiplex_output(client);
return 0;
}