changeset 7103:284dd5f2777d HEAD

Use separate idle timeouts to avoid unneededly checking them every n seconds.
author Timo Sirainen <tss@iki.fi>
date Fri, 04 Jan 2008 00:36:32 +0200
parents 75f4e7ce8151
children db5f55daa002
files src/imap/client.c src/imap/client.h src/imap/cmd-append.c src/imap/cmd-search.c src/imap/common.h src/pop3/client.c src/pop3/client.h
diffstat 7 files changed, 75 insertions(+), 82 deletions(-) [+]
line wrap: on
line diff
--- a/src/imap/client.c	Fri Jan 04 00:02:06 2008 +0200
+++ b/src/imap/client.c	Fri Jan 04 00:36:32 2008 +0200
@@ -16,10 +16,16 @@
 extern struct mail_storage_callbacks mail_storage_callbacks;
 
 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);
 
+static void client_idle_timeout(struct client *client)
+{
+	if (client->output_lock == NULL)
+		client_send_line(client, "* BYE Disconnected for inactivity.");
+	client_destroy(client, "Disconnected for inactivity");
+}
+
 struct client *client_create(int fd_in, int fd_out,
 			     struct mail_namespace *namespaces)
 {
@@ -39,6 +45,8 @@
 
 	client->io = io_add(fd_in, IO_READ, client_input, client);
         client->last_input = ioloop_time;
+	client->to_idle = timeout_add(CLIENT_IDLE_TIMEOUT_MSECS,
+				      client_idle_timeout, client);
 
 	client->command_pool = pool_alloconly_create("client command", 8192);
 	client->namespaces = namespaces;
@@ -132,6 +140,9 @@
 		imap_parser_destroy(&client->free_parser);
 	if (client->io != NULL)
 		io_remove(&client->io);
+	if (client->to_idle_output != NULL)
+		timeout_remove(&client->to_idle_output);
+	timeout_remove(&client->to_idle);
 
 	i_stream_destroy(&client->input);
 	o_stream_destroy(&client->output);
@@ -397,6 +408,7 @@
 	/* reset input idle time because command output might have taken a
 	   long time and we don't want to disconnect client immediately then */
 	client->last_input = ioloop_time;
+	timeout_reset(client->to_idle);
 
 	if (cmd->cancel) {
 		cmd->cancel = FALSE;
@@ -496,6 +508,30 @@
 	return !client->input_skip_line;
 }
 
+static void client_idle_output_timeout(struct client *client)
+{
+	client_destroy(client,
+		       "Disconnected for inactivity in reading our output");
+}
+
+bool client_handle_unfinished_cmd(struct client_command_context *cmd)
+{
+	if (!cmd->output_pending) {
+		/* need more input */
+		return FALSE;
+	}
+
+	/* output is blocking, we can execute more commands */
+	o_stream_set_flush_pending(cmd->client->output, TRUE);
+	if (cmd->client->to_idle_output == NULL) {
+		/* disconnect sooner if client isn't reading our output */
+		cmd->client->to_idle_output =
+			timeout_add(CLIENT_OUTPUT_TIMEOUT_MSECS,
+				    client_idle_output_timeout, cmd->client);
+	}
+	return TRUE;
+}
+
 static bool client_command_input(struct client_command_context *cmd)
 {
 	struct client *client = cmd->client;
@@ -509,13 +545,7 @@
 			return TRUE;
 		}
 
-		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;
+		return client_handle_unfinished_cmd(cmd);
 	}
 
 	if (cmd->tag == NULL) {
@@ -641,6 +671,7 @@
 	i_assert(client->io != NULL);
 
 	client->last_input = ioloop_time;
+	timeout_reset(client->to_idle);
 
 	bytes = i_stream_read(client->input);
 	if (bytes == -1) {
@@ -665,16 +696,14 @@
 
 static void client_output_cmd(struct client_command_context *cmd)
 {
-	struct client *client = cmd->client;
 	bool finished;
 
 	/* continue processing command */
 	finished = cmd->func(cmd) || cmd->param_error;
 
-	if (!finished) {
-		if (cmd->output_pending)
-			o_stream_set_flush_pending(client->output, TRUE);
-	} else {
+	if (!finished)
+		(void)client_handle_unfinished_cmd(cmd);
+	else {
 		/* command execution was finished */
 		client_command_free(cmd);
 	}
@@ -688,6 +717,9 @@
 	i_assert(!client->destroyed);
 
 	client->last_output = ioloop_time;
+	timeout_reset(client->to_idle);
+	if (client->to_idle_output != NULL)
+		timeout_reset(client->to_idle_output);
 
 	if ((ret = o_stream_flush(client->output)) < 0) {
 		client_destroy(client, NULL);
@@ -719,35 +751,9 @@
 	return ret;
 }
 
-static void idle_timeout(void *context ATTR_UNUSED)
-{
-	time_t idle_time, last_change;
-
-	if (my_client == NULL)
-		return;
-
-	last_change = I_MAX(my_client->last_input, my_client->last_output);
-	idle_time = ioloop_time - last_change;
-
-	if (o_stream_get_buffer_used_size(my_client->output) > 0 &&
-	    idle_time >= CLIENT_OUTPUT_TIMEOUT) {
-		/* client isn't reading our output */
-		client_destroy(my_client, "Disconnected for inactivity "
-			       "in reading our output");
-	} else if (idle_time >= CLIENT_IDLE_TIMEOUT) {
-		/* client isn't sending us anything */
-		if (my_client->output_lock == NULL) {
-			client_send_line(my_client,
-					 "* BYE Disconnected for inactivity.");
-		}
-		client_destroy(my_client, "Disconnected for inactivity");
-	}
-}
-
 void clients_init(void)
 {
 	my_client = NULL;
-	to_idle = timeout_add(10000, idle_timeout, NULL);
 }
 
 void clients_deinit(void)
@@ -756,6 +762,4 @@
 		client_send_line(my_client, "* BYE Server shutting down.");
 		client_destroy(my_client, "Server shutting down");
 	}
-
-	timeout_remove(&to_idle);
 }
--- a/src/imap/client.h	Fri Jan 04 00:02:06 2008 +0200
+++ b/src/imap/client.h	Fri Jan 04 00:36:32 2008 +0200
@@ -46,6 +46,7 @@
 	struct io *io;
 	struct istream *input;
 	struct ostream *output;
+	struct timeout *to_idle, *to_idle_output;
 
         struct mail_namespace *namespaces;
 	struct mailbox *mailbox;
@@ -110,6 +111,7 @@
 void client_command_cancel(struct client_command_context *cmd);
 void client_command_free(struct client_command_context *cmd);
 
+bool client_handle_unfinished_cmd(struct client_command_context *cmd);
 void client_continue_pending_input(struct client **_client);
 
 void client_input(struct client *client);
--- a/src/imap/cmd-append.c	Fri Jan 04 00:02:06 2008 +0200
+++ b/src/imap/cmd-append.c	Fri Jan 04 00:36:32 2008 +0200
@@ -75,12 +75,11 @@
 	o_stream_cork(client->output);
 	finished = cmd->func(cmd);
 	o_stream_uncork(client->output);
-	if (finished) {
+	if (!finished)
+		(void)client_handle_unfinished_cmd(cmd);
+	else {
 		client_command_free(cmd);
 		client_continue_pending_input(&client);
-	} else if (cmd->output_pending) {
-		/* syncing didn't send everything */
-		o_stream_set_flush_pending(client->output, TRUE);
 	}
 }
 
--- a/src/imap/cmd-search.c	Fri Jan 04 00:02:06 2008 +0200
+++ b/src/imap/cmd-search.c	Fri Jan 04 00:36:32 2008 +0200
@@ -132,12 +132,11 @@
 	finished = cmd_search_more(cmd);
 	o_stream_uncork(client->output);
 
-	if (finished) {
+	if (!finished)
+		(void)client_handle_unfinished_cmd(cmd);
+	else {
 		client_command_free(cmd);
 		client_continue_pending_input(&client);
-	} else {
-		if (cmd->output_pending)
-			o_stream_set_flush_pending(client->output, TRUE);
 	}
 }
 
--- a/src/imap/common.h	Fri Jan 04 00:02:06 2008 +0200
+++ b/src/imap/common.h	Fri Jan 04 00:36:32 2008 +0200
@@ -4,11 +4,11 @@
 #include "lib.h"
 #include "client.h"
 
-/* Disconnect client after idling this many seconds */
-#define CLIENT_IDLE_TIMEOUT (60*30)
+/* Disconnect client after idling this many milliseconds */
+#define CLIENT_IDLE_TIMEOUT_MSECS (60*30*1000)
 
 /* If we can't send anything to client for this long, disconnect the client */
-#define CLIENT_OUTPUT_TIMEOUT (5*60)
+#define CLIENT_OUTPUT_TIMEOUT_MSECS (5*60*1000)
 
 /* Stop buffering more data into output stream after this many bytes */
 #define CLIENT_OUTPUT_OPTIMAL_SIZE 2048
--- a/src/pop3/client.c	Fri Jan 04 00:02:06 2008 +0200
+++ b/src/pop3/client.c	Fri Jan 04 00:36:32 2008 +0200
@@ -23,21 +23,28 @@
    size has dropped to half of it, start reading input again. */
 #define OUTBUF_THROTTLE_SIZE 4096
 
-/* If we can't send anything for 10 minutes, disconnect the client */
-#define CLIENT_OUTPUT_TIMEOUT (10*60)
-
 /* Disconnect client when it sends too many bad commands in a row */
 #define CLIENT_MAX_BAD_COMMANDS 20
 
-/* Disconnect client after idling this many seconds */
-#define CLIENT_IDLE_TIMEOUT (10*60)
+/* Disconnect client after idling this many milliseconds */
+#define CLIENT_IDLE_TIMEOUT_MSECS (10*60*1000)
 
 static struct client *my_client; /* we don't need more than one currently */
-static struct timeout *to_idle;
 
 static void client_input(struct client *client);
 static int client_output(struct client *client);
 
+static void client_idle_timeout(struct client *client)
+{
+	if (client->cmd != NULL) {
+		client_destroy(client,
+			"Disconnected for inactivity in reading our output");
+	} else {
+		client_send_line(client, "-ERR Disconnected for inactivity.");
+		client_destroy(client, "Disconnected for inactivity");
+	}
+}
+
 static bool init_mailbox(struct client *client, const char **error_r)
 {
 	struct mail_search_arg search_arg;
@@ -152,6 +159,8 @@
 
 	client->io = io_add(fd_in, IO_READ, client_input, client);
         client->last_input = ioloop_time;
+	client->to_idle = timeout_add(CLIENT_IDLE_TIMEOUT_MSECS,
+				      client_idle_timeout, client);
 
 	client->namespaces = namespaces;
 
@@ -260,6 +269,7 @@
 
 	if (client->io != NULL)
 		io_remove(&client->io);
+	timeout_remove(&client->to_idle);
 
 	i_stream_destroy(&client->input);
 	o_stream_destroy(&client->output);
@@ -369,6 +379,7 @@
 
 	client->waiting_input = FALSE;
 	client->last_input = ioloop_time;
+	timeout_reset(client->to_idle);
 
 	switch (i_stream_read(client->input)) {
 	case -1:
@@ -422,6 +433,7 @@
 	}
 
 	client->last_output = ioloop_time;
+	timeout_reset(client->to_idle);
 
 	if (client->cmd != NULL) {
 		o_stream_cork(client->output);
@@ -443,31 +455,9 @@
 	return client->cmd == NULL;
 }
 
-static void idle_timeout(void *context ATTR_UNUSED)
-{
-	if (my_client == NULL)
-		return;
-
-	if (my_client->cmd != NULL) {
-		if (ioloop_time - my_client->last_output >=
-		    CLIENT_OUTPUT_TIMEOUT) {
-			client_destroy(my_client, "Disconnected for inactivity "
-				       "in reading our output");
-		}
-	} else {
-		if (ioloop_time - my_client->last_input >=
-		    CLIENT_IDLE_TIMEOUT) {
-			client_send_line(my_client,
-					 "-ERR Disconnected for inactivity.");
-			client_destroy(my_client, "Disconnected for inactivity");
-		}
-	}
-}
-
 void clients_init(void)
 {
 	my_client = NULL;
-	to_idle = timeout_add(10000, idle_timeout, NULL);
 }
 
 void clients_deinit(void)
@@ -476,6 +466,4 @@
 		client_send_line(my_client, "-ERR Server shutting down.");
 		client_destroy(my_client, "Server shutting down");
 	}
-
-	timeout_remove(&to_idle);
 }
--- a/src/pop3/client.h	Fri Jan 04 00:02:06 2008 +0200
+++ b/src/pop3/client.h	Fri Jan 04 00:36:32 2008 +0200
@@ -11,6 +11,7 @@
 	struct io *io;
 	struct istream *input;
 	struct ostream *output;
+	struct timeout *to_idle;
 
 	command_func_t *cmd;
 	void *cmd_context;