dovecot: Use separate per-client timeouts instead of going throu...

dovecot at dovecot.org dovecot at dovecot.org
Thu Jan 3 23:47:11 EET 2008


details:   http://hg.dovecot.org/dovecot/rev/3f5b7bebfd82
changeset: 7099:3f5b7bebfd82
user:      Timo Sirainen <tss at iki.fi>
date:      Thu Jan 03 23:46:04 2008 +0200
description:
Use separate per-client timeouts instead of going through all clients in one
timeout.

diffstat:

5 files changed, 106 insertions(+), 126 deletions(-)
src/imap-login/client-authenticate.c |   65 ++++++++++----------
src/imap-login/client.c              |  110 ++++++++++++++++------------------
src/imap-login/client.h              |    5 -
src/pop3-login/client.c              |   50 ++++-----------
src/pop3-login/client.h              |    2 

diffs (truncated from 478 to 300 lines):

diff -r becdf2eacdce -r 3f5b7bebfd82 src/imap-login/client-authenticate.c
--- a/src/imap-login/client-authenticate.c	Thu Jan 03 23:19:33 2008 +0200
+++ b/src/imap-login/client-authenticate.c	Thu Jan 03 23:46:04 2008 +0200
@@ -18,6 +18,8 @@
 #include <stdlib.h>
 
 #define IMAP_SERVICE_NAME "imap"
+
+static void client_auth_failed(struct imap_client *client);
 
 const char *client_authenticate_get_capabilities(bool secured)
 {
@@ -211,13 +213,8 @@ static void sasl_callback(struct client 
 				  NULL);
 		client_send_tagline(client, msg);
 
-		if (!client->destroyed) {
-			/* get back to normal client input. */
-			if (client->io != NULL)
-				io_remove(&client->io);
-			client->io = io_add(client->common.fd, IO_READ,
-					    client_input, client);
-		}
+		if (!client->destroyed)
+			client_auth_failed(client);
 		break;
 	case SASL_SERVER_REPLY_MASTER_FAILED:
 		if (data == NULL)
@@ -251,6 +248,33 @@ static void sasl_callback(struct client 
 	client_unref(client);
 }
 
+static int client_auth_begin(struct imap_client *client, const char *mech_name,
+			     const char *init_resp)
+{
+	client_ref(client);
+	sasl_server_auth_begin(&client->common, IMAP_SERVICE_NAME, mech_name,
+			       init_resp, sasl_callback);
+	if (!client->common.authenticating)
+		return 1;
+
+	/* don't handle input until we get the initial auth reply */
+	if (client->io != NULL)
+		io_remove(&client->io);
+	client_set_auth_waiting(client);
+	return 0;
+}
+
+static void client_auth_failed(struct imap_client *client)
+{
+	/* get back to normal client input. */
+	if (client->io != NULL)
+		io_remove(&client->io);
+	client->io = io_add(client->common.fd, IO_READ,
+			    client_input, client);
+
+	timeout_remove(&client->to_auth_waiting);
+}
+
 int cmd_authenticate(struct imap_client *client, const struct imap_arg *args)
 {
 	const char *mech_name, *init_resp = NULL;
@@ -269,17 +293,7 @@ int cmd_authenticate(struct imap_client 
 	mech_name = IMAP_ARG_STR(&args[0]);
 	if (*mech_name == '\0')
 		return -1;
-
-	client_ref(client);
-	sasl_server_auth_begin(&client->common, IMAP_SERVICE_NAME, mech_name,
-			       init_resp, sasl_callback);
-	if (!client->common.authenticating)
-		return 1;
-
-	/* don't handle input until we get the initial auth reply */
-	if (client->io != NULL)
-		io_remove(&client->io);
-	return 0;
+	return client_auth_begin(client, mech_name, init_resp);
 }
 
 int cmd_login(struct imap_client *client, const struct imap_arg *args)
@@ -322,16 +336,5 @@ int cmd_login(struct imap_client *client
 	base64 = buffer_create_dynamic(pool_datastack_create(),
         			MAX_BASE64_ENCODED_SIZE(plain_login->used));
 	base64_encode(plain_login->data, plain_login->used, base64);
-
-	client_ref(client);
-	sasl_server_auth_begin(&client->common, IMAP_SERVICE_NAME, "PLAIN",
-			       str_c(base64), sasl_callback);
-	if (!client->common.authenticating)
-		return 1;
-
-	/* don't read any input from client until login is finished */
-	if (client->io != NULL)
-		io_remove(&client->io);
-
-	return 0;
-}
+	return client_auth_begin(client, "PLAIN", str_c(base64));
+}
diff -r becdf2eacdce -r 3f5b7bebfd82 src/imap-login/client.c
--- a/src/imap-login/client.c	Thu Jan 03 23:19:33 2008 +0200
+++ b/src/imap-login/client.c	Thu Jan 03 23:46:04 2008 +0200
@@ -28,8 +28,8 @@
 /* maximum length for IMAP command line. */
 #define MAX_IMAP_LINE 8192
 
-/* Disconnect client after idling this many seconds */
-#define CLIENT_LOGIN_IDLE_TIMEOUT (3*60)
+/* Disconnect client after idling this many milliseconds */
+#define CLIENT_LOGIN_IDLE_TIMEOUT_MSECS (3*60*1000)
 
 /* Disconnect client when it sends too many bad commands */
 #define CLIENT_MAX_BAD_COMMANDS 10
@@ -39,21 +39,21 @@
    client hash, it's faster if we disconnect multiple clients. */
 #define CLIENT_DESTROY_OLDEST_COUNT 16
 
-/* If we've been waiting auth server to respond for over this many seconds,
+/* If we've been waiting auth server to respond for over this many milliseconds,
    send a "waiting" message. */
-#define AUTH_WAITING_TIMEOUT 30
-
-#if CLIENT_LOGIN_IDLE_TIMEOUT >= AUTH_REQUEST_TIMEOUT
+#define AUTH_WAITING_TIMEOUT_MSECS 30
+
+#if CLIENT_LOGIN_IDLE_TIMEOUT_MSECS >= AUTH_REQUEST_TIMEOUT*1000
 #  error client idle timeout must be smaller than authentication timeout
 #endif
 
+#define AUTH_WAITING_MSG \
+	"* OK Waiting for authentication process to respond.."
+
 const char *login_protocol = "IMAP";
 const char *capability_string = CAPABILITY_STRING;
 
 static struct hash_table *clients;
-static struct timeout *to_idle;
-
-static void idle_timeout(void *context);
 
 static void client_set_title(struct imap_client *client)
 {
@@ -345,7 +345,7 @@ bool client_read(struct imap_client *cli
 
 void client_input(struct imap_client *client)
 {
-	client->last_input = ioloop_time;
+	timeout_reset(client->to_idle_disconnect);
 
 	if (!client_read(client))
 		return;
@@ -355,12 +355,12 @@ void client_input(struct imap_client *cl
 	if (!auth_client_is_connected(auth_client)) {
 		/* we're not yet connected to auth process -
 		   don't allow any commands */
-		client->waiting_sent = TRUE;
-		client_send_line(client,
-			"* OK Waiting for authentication process to respond..");
+		client_send_line(client, AUTH_WAITING_MSG);
+		if (client->to_auth_waiting != NULL)
+			timeout_remove(&client->to_auth_waiting);
+
 		client->input_blocked = TRUE;
 	} else {
-		client->waiting_sent = FALSE;
 		o_stream_cork(client->output);
 		while (client_handle_input(client)) ;
 		o_stream_uncork(client->output);
@@ -425,6 +425,26 @@ static void client_send_greeting(struct 
 	client->greeting_sent = TRUE;
 }
 
+static void client_idle_disconnect_timeout(struct imap_client *client)
+{
+	client_send_line(client, "* BYE Disconnected for inactivity.");
+	client_destroy(client, "Disconnected: Inactivity");
+}
+
+static void client_auth_waiting_timeout(struct imap_client *client)
+{
+	client_send_line(client, AUTH_WAITING_MSG);
+	timeout_remove(&client->to_auth_waiting);
+}
+
+void client_set_auth_waiting(struct imap_client *client)
+{
+	i_assert(client->to_auth_waiting == NULL);
+	client->to_auth_waiting =
+		timeout_add(AUTH_WAITING_TIMEOUT_MSECS,
+			    client_auth_waiting_timeout, client);
+}
+
 struct client *client_create(int fd, bool ssl, const struct ip_addr *local_ip,
 			     const struct ip_addr *ip)
 {
@@ -450,17 +470,19 @@ struct client *client_create(int fd, boo
 	client_open_streams(client, fd);
 	client->io = io_add(fd, IO_READ, client_input, client);
 
-	client->last_input = ioloop_time;
 	hash_insert(clients, client, client);
 
 	main_ref();
 
 	if (!greeting_capability || auth_client_is_connected(auth_client))
-                client_send_greeting(client);
+		client_send_greeting(client);
+	else
+		client_set_auth_waiting(client);
 	client_set_title(client);
 
-	if (to_idle == NULL)
-		to_idle = timeout_add(1000, idle_timeout, NULL);
+	client->to_idle_disconnect =
+		timeout_add(CLIENT_LOGIN_IDLE_TIMEOUT_MSECS,
+			    client_idle_disconnect_timeout, client);
 	return &client->common;
 }
 
@@ -474,8 +496,6 @@ void client_destroy(struct imap_client *
 		client_syslog(&client->common, reason);
 
 	hash_remove(clients, client);
-	if (hash_count(clients) == 0)
-		timeout_remove(&to_idle);
 
 	if (client->input != NULL)
 		i_stream_close(client->input);
@@ -494,6 +514,10 @@ void client_destroy(struct imap_client *
 
 	if (client->io != NULL)
 		io_remove(&client->io);
+	if (client->to_idle_disconnect != NULL)
+		timeout_remove(&client->to_idle_disconnect);
+	if (client->to_auth_waiting != NULL)
+		timeout_remove(&client->to_auth_waiting);
 
 	if (client->common.fd != -1) {
 		net_disconnect(client->common.fd);
@@ -584,21 +608,12 @@ void client_send_tagline(struct imap_cli
 	client_send_line(client, t_strconcat(client->cmd_tag, " ", line, NULL));
 }
 
-static void client_check_idle(struct imap_client *client)
-{
-	if (ioloop_time - client->last_input >= CLIENT_LOGIN_IDLE_TIMEOUT) {
-		client_send_line(client, "* BYE Disconnected for inactivity.");
-		client_destroy(client, "Disconnected: Inactivity");
-	} else if (!client->waiting_sent &&
-		   ioloop_time - client->last_input > AUTH_WAITING_TIMEOUT &&
-		   (client->common.authenticating || !client->greeting_sent)) {
-		client->waiting_sent = TRUE;
-		client_send_line(client,
-			"* OK Waiting for authentication process to respond..");
-	}
-}
-
-static void idle_timeout(void *context ATTR_UNUSED)
+unsigned int clients_get_count(void)
+{
+	return hash_count(clients);
+}
+
+void clients_notify_auth_connected(void)
 {
 	struct hash_iterate_context *iter;
 	void *key, *value;
@@ -607,25 +622,8 @@ static void idle_timeout(void *context A
 	while (hash_iterate(iter, &key, &value)) {
 		struct imap_client *client = key;
 
-		client_check_idle(client);
-	}
-	hash_iterate_deinit(&iter);
-}
-
-unsigned int clients_get_count(void)
-{
-	return hash_count(clients);
-}
-
-void clients_notify_auth_connected(void)
-{
-	struct hash_iterate_context *iter;
-	void *key, *value;
-
-	iter = hash_iterate_init(clients);
-	while (hash_iterate(iter, &key, &value)) {
-		struct imap_client *client = key;
-
+		if (client->to_auth_waiting != NULL)
+			timeout_remove(&client->to_auth_waiting);
 		if (!client->greeting_sent)
 			client_send_greeting(client);
 		if (client->input_blocked) {
@@ -659,6 +657,4 @@ void clients_deinit(void)
 {
 	clients_destroy_all();
 	hash_destroy(&clients);


More information about the dovecot-cvs mailing list