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;
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
*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));
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);
}
}
-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);
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);