dovecot: If client is sending a lot of commands at once, stop re...

dovecot at dovecot.org dovecot at dovecot.org
Sat Dec 22 01:59:46 EET 2007


details:   http://hg.dovecot.org/dovecot/rev/08a3ba5de497
changeset: 7019:08a3ba5de497
user:      Timo Sirainen <tss at iki.fi>
date:      Sat Dec 22 01:59:42 2007 +0200
description:
If client is sending a lot of commands at once, stop reading input instead
of sending "BAD Too long argument".

diffstat:

1 file changed, 50 insertions(+), 27 deletions(-)
src/imap/client.c |   77 ++++++++++++++++++++++++++++++++++-------------------

diffs (146 lines):

diff -r b83be2b6ac8f -r 08a3ba5de497 src/imap/client.c
--- a/src/imap/client.c	Sat Dec 22 01:19:11 2007 +0200
+++ b/src/imap/client.c	Sat Dec 22 01:59:42 2007 +0200
@@ -17,6 +17,8 @@ extern struct mail_storage_callbacks mai
 
 static struct client *my_client; /* we don't need more than one currently */
 static struct timeout *to_idle;
+
+static bool client_handle_input(struct client *client);
 
 struct client *client_create(int fd_in, int fd_out,
 			     struct mail_namespace *namespaces)
@@ -472,7 +474,7 @@ void client_continue_pending_input(struc
 	/* if there's unread data in buffer, handle it. */
 	(void)i_stream_get_data(client->input, &size);
 	if (size > 0)
-		client_input(client);
+		(void)client_handle_input(client);
 }
 
 /* Skip incoming data until newline is found,
@@ -509,9 +511,12 @@ static bool client_command_input(struct 
 			return TRUE;
 		}
 
-		/* unfinished */
-		if (cmd->output_pending)
+		if (cmd->output_pending) {
+			/* output is blocking, we can execute more commands */
 			o_stream_set_flush_pending(client->output, TRUE);
+			return TRUE;
+		}
+		/* need more input */
 		return FALSE;
 	}
 
@@ -563,13 +568,17 @@ static bool client_command_input(struct 
 	}
 }
 
-static bool client_handle_next_command(struct client *client)
+static int client_handle_next_command(struct client *client, bool *remove_io_r)
 {
 	size_t size;
 
+	*remove_io_r = FALSE;
+
 	if (client->input_lock != NULL) {
-		if (client->input_lock->waiting_unambiguity)
+		if (client->input_lock->waiting_unambiguity) {
+			*remove_io_r = TRUE;
 			return FALSE;
+		}
 		return client_command_input(client->input_lock);
 	}
 
@@ -590,7 +599,7 @@ static bool client_handle_next_command(s
 	if (client->command_queue_size >= CLIENT_COMMAND_QUEUE_MAX_SIZE ||
 	    client->output_lock != NULL) {
 		/* wait for some of the commands to finish */
-		io_remove(&client->io);
+		*remove_io_r = TRUE;
 		return FALSE;
 	}
 
@@ -598,21 +607,51 @@ static bool client_handle_next_command(s
 	return client_command_input(client->input_lock);
 }
 
+static bool client_handle_input(struct client *client)
+{
+	bool ret, remove_io, handled_commands = FALSE;
+
+	o_stream_cork(client->output);
+	client->handling_input = TRUE;
+	do {
+		T_FRAME(
+			ret = client_handle_next_command(client, &remove_io);
+		);
+		if (ret)
+			handled_commands = TRUE;
+	} while (ret && !client->disconnected);
+	client->handling_input = FALSE;
+	o_stream_uncork(client->output);
+
+	if (client->output->closed) {
+		client_destroy(client, NULL);
+		return TRUE;
+	} else {
+		if (remove_io)
+			io_remove(&client->io);
+		else
+			client_add_missing_io(client);
+		return handled_commands;
+	}
+}
+
 void client_input(struct client *client)
 {
 	struct client_command_context *cmd;
-	int ret;
+	ssize_t bytes;
 
 	i_assert(client->io != NULL);
 
 	client->last_input = ioloop_time;
 
-	switch (i_stream_read(client->input)) {
-	case -1:
+	bytes = i_stream_read(client->input);
+	if (bytes == -1) {
 		/* disconnected */
 		client_destroy(client, NULL);
 		return;
-	case -2:
+	}
+
+	if (!client_handle_input(client) && bytes == -2) {
 		/* parameter word is longer than max. input buffer size.
 		   this is most likely an error, so skip the new data
 		   until newline is found. */
@@ -623,23 +662,7 @@ void client_input(struct client *client)
 		cmd->param_error = TRUE;
 		client_send_command_error(cmd, "Too long argument.");
 		client_command_free(cmd);
-		return;
-	}
-
-	o_stream_cork(client->output);
-	client->handling_input = TRUE;
-	do {
-		T_FRAME(
-			ret = client_handle_next_command(client);
-		);
-	} while (ret && !client->disconnected);
-	client->handling_input = FALSE;
-	o_stream_uncork(client->output);
-
-	if (client->output->closed)
-		client_destroy(client, NULL);
-	else
-		client_add_missing_io(client);
+	}
 }
 
 static void client_output_cmd(struct client_command_context *cmd)


More information about the dovecot-cvs mailing list