]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
anvil: Read from FIFOs in packets instead of using streams.
authorTimo Sirainen <tss@iki.fi>
Fri, 4 Sep 2009 17:47:16 +0000 (13:47 -0400)
committerTimo Sirainen <tss@iki.fi>
Fri, 4 Sep 2009 17:47:16 +0000 (13:47 -0400)
--HG--
branch : HEAD

src/anvil/anvil-connection.c
src/anvil/anvil-connection.h
src/anvil/main.c

index 79675334b32114ec63a70190596705f7e3f22bd0..269970bd4bee8bcad23aace14ecd0b7d1f767dfa 100644 (file)
@@ -24,6 +24,8 @@ struct anvil_connection {
        struct istream *input;
        struct ostream *output;
        struct io *io;
+       unsigned char *fifo_inbuf;
+       size_t fifo_inbuf_size;
 
        unsigned int version_received:1;
        unsigned int handshaked:1;
@@ -32,16 +34,41 @@ struct anvil_connection {
 
 struct anvil_connection *anvil_connections = NULL;
 
+static const char *
+anvil_connection_fifo_read_line(struct anvil_connection *conn)
+{
+       ssize_t ret;
+
+       ret = read(conn->fd, conn->fifo_inbuf, conn->fifo_inbuf_size);
+       if (ret > 0) {
+               if (conn->fifo_inbuf[ret-1] != '\n') {
+                       i_error("BUG: Client packet didn't end with LF");
+                       return NULL;
+               }
+               conn->fifo_inbuf[ret-1] = '\0';
+               return (const char *)conn->fifo_inbuf;
+       }
+       if (ret == 0) {
+               /* disconnected */
+       } else {
+               if (errno == EAGAIN)
+                       return NULL;
+               i_error("read() failed: %m");
+       }
+       anvil_connection_destroy(conn);
+       return NULL;
+}
+
 static const char *const *
 anvil_connection_next_line(struct anvil_connection *conn)
 {
        const char *line;
 
-       line = i_stream_next_line(conn->input);
-       if (line == NULL)
-               return NULL;
-
-       return t_strsplit(line, "\t");
+       if (conn->input != NULL)
+               line = i_stream_next_line(conn->input);
+       else
+               line = anvil_connection_fifo_read_line(conn);
+       return line == NULL ? NULL : t_strsplit(line, "\t");
 }
 
 static int
@@ -86,6 +113,10 @@ anvil_connection_request(struct anvil_connection *conn,
                        *error_r = "LOOKUP: Not enough parameters";
                        return -1;
                }
+               if (conn->output == NULL) {
+                       *error_r = "LOOKUP on a FIFO, can't send reply";
+                       return -1;
+               }
                count = connect_limit_lookup(connect_limit, args[0]);
                (void)o_stream_send_str(conn->output,
                                        t_strdup_printf("%u\n", count));
@@ -99,26 +130,28 @@ anvil_connection_request(struct anvil_connection *conn,
 static void anvil_connection_input(void *context)
 {
        struct anvil_connection *conn = context;
-       const char *const *args, *line, *error;
-
-       switch (i_stream_read(conn->input)) {
-       case -2:
-               i_error("BUG: Anvil client connection sent too much data");
-                anvil_connection_destroy(conn);
-               return;
-       case -1:
-                anvil_connection_destroy(conn);
-               return;
+       const char *const *args, *error;
+
+       if (conn->input != NULL) {
+               switch (i_stream_read(conn->input)) {
+               case -2:
+                       i_error("BUG: Anvil client connection sent too "
+                               "much data");
+                       anvil_connection_destroy(conn);
+                       return;
+               case -1:
+                       anvil_connection_destroy(conn);
+                       return;
+               }
        }
 
        if (!conn->version_received) {
-               line = i_stream_next_line(conn->input);
-               if (line == NULL)
+               if ((args = anvil_connection_next_line(conn)) == NULL)
                        return;
 
-               if (strncmp(line, "VERSION\t", 8) != 0 ||
-                   atoi(t_strcut(line + 8, '\t')) !=
-                   ANVIL_CLIENT_PROTOCOL_MAJOR_VERSION) {
+               if (str_array_length(args) < 3 ||
+                   strcmp(args[0], "VERSION") != 0 ||
+                   atoi(args[1]) != ANVIL_CLIENT_PROTOCOL_MAJOR_VERSION) {
                        i_error("Anvil client not compatible with this server "
                                "(mixed old and new binaries?)");
                        anvil_connection_destroy(conn);
@@ -135,14 +168,20 @@ static void anvil_connection_input(void *context)
        }
 }
 
-struct anvil_connection *anvil_connection_create(int fd, bool master)
+struct anvil_connection *
+anvil_connection_create(int fd, bool master, bool fifo)
 {
        struct anvil_connection *conn;
 
        conn = i_new(struct anvil_connection, 1);
        conn->fd = fd;
-       conn->input = i_stream_create_fd(fd, MAX_INBUF_SIZE, FALSE);
-       conn->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
+       if (!fifo) {
+               conn->input = i_stream_create_fd(fd, MAX_INBUF_SIZE, FALSE);
+               conn->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
+       } else {
+               conn->fifo_inbuf_size = MAX_INBUF_SIZE;
+               conn->fifo_inbuf = i_malloc(conn->fifo_inbuf_size);
+       }
        conn->io = io_add(fd, IO_READ, anvil_connection_input, conn);
        conn->master = master;
        DLLIST_PREPEND(&anvil_connections, conn);
@@ -154,10 +193,13 @@ void anvil_connection_destroy(struct anvil_connection *conn)
        DLLIST_REMOVE(&anvil_connections, conn);
 
        io_remove(&conn->io);
-       i_stream_destroy(&conn->input);
-       o_stream_destroy(&conn->output);
+       if (conn->input != NULL)
+               i_stream_destroy(&conn->input);
+       if (conn->output != NULL)
+               o_stream_destroy(&conn->output);
        if (close(conn->fd) < 0)
                i_error("close(anvil conn) failed: %m");
+       i_free(conn->fifo_inbuf);
        i_free(conn);
 
        master_service_client_connection_destroyed(master_service);
index 453de264c53fd866e3673ad4ece5b91f19ee43d7..f94fbabe097848b7bca13a0e3a77d5cb09d57218 100644 (file)
@@ -1,7 +1,8 @@
 #ifndef ANVIL_CONNECTION_H
 #define ANVIL_CONNECTION_H
 
-struct anvil_connection *anvil_connection_create(int fd, bool master);
+struct anvil_connection *
+anvil_connection_create(int fd, bool master, bool fifo);
 void anvil_connection_destroy(struct anvil_connection *conn);
 
 void anvil_connections_destroy_all(void);
index 31b1b6a2ec5f1174ba3de3bb5f178d43b938b574..18b991be006c69f73dd6dc624b52ba76c73d108c 100644 (file)
@@ -17,7 +17,7 @@ static void client_connected(const struct master_service_connection *conn)
 {
        bool master = conn->listen_fd == MASTER_LISTEN_FD_FIRST;
 
-       anvil_connection_create(conn->fd, master);
+       anvil_connection_create(conn->fd, master, conn->fifo);
 }
 
 int main(int argc, char *argv[])