]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
imap-hibernate: If unhibernation fails, make sure imap process won't finish it later on
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Thu, 23 Mar 2023 23:41:37 +0000 (01:41 +0200)
committeraki.tuomi <aki.tuomi@open-xchange.com>
Fri, 24 Mar 2023 11:14:36 +0000 (11:14 +0000)
Especially if unhibernation fails due to a connection timeout to imap
process due to high load, it's possible that the imap process will
eventually finish the unhibernation and continue with the client. This is
rather confusing, since imap-hibernate process already logged that the
client got disconnected.

src/imap-hibernate/imap-client.c

index 3c70a43297fa3b138002faeebd553c12b04f8bb0..2ee8c77e663bc305b760240cedd659516d62cda7 100644 (file)
@@ -80,6 +80,7 @@ struct imap_client {
        bool bad_done, idle_done;
        bool unhibernate_queued;
        bool input_pending;
+       bool shutdown_fd_on_destroy;
 };
 
 static struct imap_client *imap_clients;
@@ -218,6 +219,10 @@ imap_client_move_back_send_callback(void *context, struct ostream *output)
                imap_client_unhibernate_failed(&client, error);
                return;
        }
+       /* If unhibernation fails after this, shutdown() the fd to make sure
+          the imap process won't later on finish unhibernation after all and
+          cause confusion. */
+       client->shutdown_fd_on_destroy = TRUE;
        i_assert(ret > 0);
        o_stream_nsend(output, str_data(str) + 1, str_len(str) - 1);
 }
@@ -231,6 +236,7 @@ imap_client_move_back_read_callback(void *context, const char *line)
                /* failed - FIXME: retry later? */
                imap_client_unhibernate_failed(&client, line+1);
        } else {
+               client->shutdown_fd_on_destroy = FALSE;
                imap_client_destroy(&client, NULL);
        }
 }
@@ -698,6 +704,11 @@ void imap_client_destroy(struct imap_client **_client, const char *reason)
        if (client->state.tag != NULL)
                i_free(client->state.tag);
 
+       if (client->shutdown_fd_on_destroy) {
+               if (shutdown(client->fd, SHUT_RDWR) < 0)
+                       e_error(client->event, "shutdown() failed: %m");
+       }
+
        DLLIST_REMOVE(&imap_clients, client);
        imap_client_stop(client);
        i_stream_destroy(&client->input);