]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
imap: Cleaned up "command pending" handling code. Should fix hangs caused by recent...
authorTimo Sirainen <tss@iki.fi>
Tue, 26 May 2009 18:21:59 +0000 (14:21 -0400)
committerTimo Sirainen <tss@iki.fi>
Tue, 26 May 2009 18:21:59 +0000 (14:21 -0400)
--HG--
branch : HEAD

src/imap/cmd-append.c
src/imap/cmd-idle.c
src/imap/imap-client.c
src/imap/imap-client.h
src/imap/imap-search.c

index b37252e6fb595134f2be220a2b981056949d6f4e..b89df3086b88f62f0b5d8aa78c0cb64da388d22b 100644 (file)
@@ -44,7 +44,6 @@ static void client_input_append(struct client_command_context *cmd)
 {
        struct cmd_append_context *ctx = cmd->context;
        struct client *client = cmd->client;
-       struct ostream *output = client->output;
        bool finished;
 
        i_assert(!client->destroyed);
@@ -80,17 +79,19 @@ static void client_input_append(struct client_command_context *cmd)
                return;
        }
 
-       o_stream_ref(output);
-       o_stream_cork(output);
+       o_stream_cork(client->output);
        finished = cmd->func(cmd);
        if (!finished && cmd->state != CLIENT_COMMAND_STATE_DONE)
                (void)client_handle_unfinished_cmd(cmd);
        else
                client_command_free(&cmd);
        (void)cmd_sync_delayed(client);
-       client_continue_pending_input(&client);
-       o_stream_uncork(output);
-       o_stream_unref(&output);
+       o_stream_uncork(client->output);
+
+       if (client->disconnected)
+               client_destroy(client, NULL);
+       else
+               client_continue_pending_input(client);
 }
 
 /* Returns -1 = error, 0 = need more data, 1 = successful. flags and
index 3e83a8adcc70cfae5886acbcd67beb60ed5ff305..6574bd67e378c9a2c9ff5020b2ae400cf814d1cd 100644 (file)
@@ -69,7 +69,7 @@ static void idle_client_input(struct cmd_idle_context *ctx)
        case -2:
                client->input_skip_line = TRUE;
                idle_finish(ctx, FALSE, TRUE);
-               client_continue_pending_input(&client);
+               client_continue_pending_input(client);
                return;
        }
 
@@ -85,10 +85,13 @@ static void idle_client_input(struct cmd_idle_context *ctx)
                        client->input_skip_line = FALSE;
                else {
                        idle_finish(ctx, strcasecmp(line, "DONE") == 0, TRUE);
-                       client_continue_pending_input(&client);
                        break;
                }
        }
+       if (client->disconnected)
+               client_destroy(client, NULL);
+       else
+               client_continue_pending_input(client);
 }
 
 static void keepalive_timeout(struct cmd_idle_context *ctx)
index 591bdbabd03d12004511935f4ef9613d04dcc96a..d1b4e5ce54a623d3388a347abf4597a238ef54d8 100644 (file)
@@ -534,20 +534,12 @@ static void client_add_missing_io(struct client *client)
        }
 }
 
-void client_continue_pending_input(struct client **_client)
+void client_continue_pending_input(struct client *client)
 {
-       struct client *client = *_client;
        size_t size;
 
        i_assert(!client->handling_input);
 
-       if (client->disconnected) {
-               if (!client->destroyed)
-                       client_destroy(client, NULL);
-               *_client = NULL;
-               return;
-       }
-
        if (client->input_lock != NULL) {
                /* there's a command that has locked the input */
                struct client_command_context *cmd = client->input_lock;
@@ -559,8 +551,10 @@ void client_continue_pending_input(struct client **_client)
                   commands to finish. */
                if (client_command_check_ambiguity(cmd)) {
                        /* we could be waiting for existing sync to finish */
-                       cmd_sync_delayed(client);
-                       return;
+                       if (!cmd_sync_delayed(client))
+                               return;
+                       if (client_command_check_ambiguity(cmd))
+                               return;
                }
                cmd->state = CLIENT_COMMAND_STATE_WAIT_INPUT;
        }
@@ -569,8 +563,10 @@ void client_continue_pending_input(struct client **_client)
 
        /* if there's unread data in buffer, handle it. */
        (void)i_stream_get_data(client->input, &size);
-       if (size > 0)
-               (void)client_handle_input(client);
+       if (size > 0 && !client->disconnected) {
+               if (client_handle_input(client))
+                       client_continue_pending_input(client);
+       }
 }
 
 /* Skip incoming data until newline is found,
@@ -730,6 +726,8 @@ bool client_handle_input(struct client *client)
 {
        bool ret, remove_io, handled_commands = FALSE;
 
+       i_assert(!client->disconnected);
+
        client->handling_input = TRUE;
        do {
                T_BEGIN {
@@ -740,23 +738,16 @@ bool client_handle_input(struct client *client)
        } while (ret && !client->disconnected && client->io != NULL);
        client->handling_input = FALSE;
 
-       if (client->output->closed) {
-               client_destroy(client, NULL);
-               return TRUE;
-       } else {
-               if (remove_io)
-                       io_remove(&client->io);
-               else
-                       client_add_missing_io(client);
-               if (!handled_commands)
-                       return FALSE;
+       if (remove_io)
+               io_remove(&client->io);
+       else
+               client_add_missing_io(client);
+       if (!handled_commands)
+               return FALSE;
 
-               ret = client->input_lock != NULL ? TRUE :
-                       cmd_sync_delayed(client);
-               if (ret)
-                       client_continue_pending_input(&client);
-               return TRUE;
-       }
+       if (client->input_lock == NULL)
+               cmd_sync_delayed(client);
+       return TRUE;
 }
 
 void client_input(struct client *client)
@@ -793,6 +784,11 @@ void client_input(struct client *client)
        }
        o_stream_uncork(output);
        o_stream_unref(&output);
+
+       if (client->disconnected)
+               client_destroy(client, NULL);
+       else
+               client_continue_pending_input(client);
 }
 
 static void client_output_cmd(struct client_command_context *cmd)
@@ -855,15 +851,13 @@ int client_output(struct client *client)
                }
        }
 
-       if (client->output->closed) {
+       (void)cmd_sync_delayed(client);
+       o_stream_uncork(client->output);
+       if (client->disconnected)
                client_destroy(client, NULL);
-               return 1;
-       } else {
-               (void)cmd_sync_delayed(client);
-               o_stream_uncork(client->output);
-               client_continue_pending_input(&client);
-               return ret;
-       }
+       else
+               client_continue_pending_input(client);
+       return ret;
 }
 
 bool client_handle_search_save_ambiguity(struct client_command_context *cmd)
index d86f9e167fa2929f5427de1915911cb0dc55c80a..e40d56f5e4cb3573ad018764bf22ec7a6b681b15 100644 (file)
@@ -191,7 +191,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_continue_pending_input(struct client *client);
 
 void client_input(struct client *client);
 bool client_handle_input(struct client *client);
index e0b0e07a6d4b458b6f79d84e930a797b0fb75903..8a979a31ca9e491b2a9707476e6ba3b3a58363c3 100644 (file)
@@ -439,7 +439,11 @@ static void cmd_search_more_callback(struct client_command_context *cmd)
        else
                client_command_free(&cmd);
        (void)cmd_sync_delayed(client);
-       client_continue_pending_input(&client);
+
+       if (client->disconnected)
+               client_destroy(client, NULL);
+       else
+               client_continue_pending_input(client);
 }
 
 int cmd_search_parse_return_if_found(struct imap_search_context *ctx,