dovecot-1.1: Don't try to call a cancelled command if it hasn't ...

dovecot at dovecot.org dovecot at dovecot.org
Sat May 31 13:59:49 EEST 2008


details:   http://hg.dovecot.org/dovecot-1.1/rev/a99b9735f875
changeset: 7583:a99b9735f875
user:      Timo Sirainen <tss at iki.fi>
date:      Sat May 31 13:59:46 2008 +0300
description:
Don't try to call a cancelled command if it hasn't started running. Cancel
the input-waiting command last. These should fix "Trying to close mailbox
with open transactions" assert when client disconnects.

diffstat:

1 file changed, 26 insertions(+), 4 deletions(-)
src/imap/client.c |   30 ++++++++++++++++++++++++++----

diffs (51 lines):

diff -r 8e7a15987428 -r a99b9735f875 src/imap/client.c
--- a/src/imap/client.c	Sat May 31 13:47:11 2008 +0300
+++ b/src/imap/client.c	Sat May 31 13:59:46 2008 +0300
@@ -71,8 +71,26 @@ void client_command_cancel(struct client
 	struct client_command_context *cmd = *_cmd;
 	bool cmd_ret;
 
-	cmd->cancel = TRUE;
-	cmd_ret = cmd->func == NULL ? TRUE : cmd->func(cmd);
+	switch (cmd->state) {
+	case CLIENT_COMMAND_STATE_WAIT_INPUT:
+		/* a bit kludgy check: cancel command only if it has context
+		   set. currently only append command matches this check. all
+		   other commands haven't even started the processing yet. */
+		if (cmd->context == NULL)
+			break;
+		/* fall through */
+	case CLIENT_COMMAND_STATE_WAIT_OUTPUT:
+		cmd->cancel = TRUE;
+		break;
+	case CLIENT_COMMAND_STATE_WAIT_UNAMBIGUITY:
+	case CLIENT_COMMAND_STATE_WAIT_SYNC:
+		/* commands haven't started yet */
+		break;
+	case CLIENT_COMMAND_STATE_DONE:
+		i_unreached();
+	}
+
+	cmd_ret = !cmd->cancel || cmd->func == NULL ? TRUE : cmd->func(cmd);
 	if (!cmd_ret && cmd->state != CLIENT_COMMAND_STATE_DONE) {
 		if (cmd->client->output->closed)
 			i_panic("command didn't cancel itself: %s", cmd->name);
@@ -130,12 +148,16 @@ void client_destroy(struct client *clien
 	/* finish off all the queued commands. */
 	if (client->output_lock != NULL)
 		client_command_cancel(&client->output_lock);
-	if (client->input_lock != NULL)
-		client_command_cancel(&client->input_lock);
 	while (client->command_queue != NULL) {
 		cmd = client->command_queue;
 		client_command_cancel(&cmd);
 	}
+	/* handle the input_lock command last. it might have been waiting on
+	   other queued commands (although we probably should just drop the
+	   command at that point since it hasn't started running. but this may
+	   change in future). */
+	if (client->input_lock != NULL)
+		client_command_cancel(&client->input_lock);
 
 	if (client->mailbox != NULL)
 		mailbox_close(&client->mailbox);


More information about the dovecot-cvs mailing list