config-connection.c revision a64adf62fa33f2463a86f990217b0c9078531a40
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen/* Copyright (C) 2005 Timo Sirainen */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "common.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "str.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "ioloop.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "network.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "istream.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "ostream.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "config-connection.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include <stdlib.h>
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include <unistd.h>
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include <fcntl.h>
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#define MAX_INBUF_SIZE 1024
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#define CONFIG_CLIENT_PROTOCOL_MAJOR_VERSION 1
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#define CONFIG_CLIENT_PROTOCOL_MINOR_VERSION 0
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenstruct config_connection {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen int fd;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen struct istream *input;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen struct ostream *output;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen struct io *io;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen unsigned int version_received:1;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen unsigned int handshaked:1;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen};
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenstatic const char *const *
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenconfig_connection_next_line(struct config_connection *conn)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen const char *line;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen line = i_stream_next_line(conn->input);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (line == NULL)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return NULL;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return t_strsplit(line, "\t");
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen}
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenstatic void config_connection_request(struct config_connection *conn,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen const char *const *args)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* <process> [<args>] */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen // FIXME
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen o_stream_send(conn->output, str_data(config_string),
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen str_len(config_string));
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen o_stream_flush(conn->output);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen}
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenstatic void config_connection_input(void *context)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen struct config_connection *conn = context;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen const char *const *args, *line;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen switch (i_stream_read(conn->input)) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen case -2:
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen i_error("BUG: Config client connection sent too much data");
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen config_connection_destroy(conn);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen case -1:
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen config_connection_destroy(conn);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (!conn->version_received) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen line = i_stream_next_line(conn->input);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (line == NULL)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (strncmp(line, "VERSION\t", 8) != 0 ||
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen atoi(t_strcut(line + 8, '\t')) !=
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen CONFIG_CLIENT_PROTOCOL_MAJOR_VERSION) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen i_error("Config client not compatible with this server "
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen "(mixed old and new binaries?)");
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen config_connection_destroy(conn);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen conn->version_received = TRUE;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen t_push();
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen while ((args = config_connection_next_line(conn)) != NULL) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (args[0] == NULL)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen continue;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (strcmp(args[0], "REQ") == 0)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen config_connection_request(conn, args + 1);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen t_pop();
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen}
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenstruct config_connection *config_connection_create(int fd)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen struct config_connection *conn;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen conn = i_new(struct config_connection, 1);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen conn->fd = fd;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen conn->input = i_stream_create_fd(fd, MAX_INBUF_SIZE, FALSE);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen conn->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen conn->io = io_add(fd, IO_READ, config_connection_input, conn);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return conn;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen}
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenvoid config_connection_destroy(struct config_connection *conn)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen io_remove(&conn->io);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen i_stream_destroy(&conn->input);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen o_stream_destroy(&conn->output);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (close(conn->fd) < 0)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen i_error("close(config conn) failed: %m");
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen i_free(conn);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen}
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenvoid config_connection_dump_request(int fd, const char *service)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen struct config_connection *conn;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen const char *args[2] = { service, NULL };
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen conn = config_connection_create(fd);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen config_connection_request(conn, args);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen config_connection_destroy(conn);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen}