]> 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, 12 May 2023 13:03:46 +0000 (13:03 +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 8e0f93381b4c27cf62f0c021195b0056939017ff..fa5eddef308870647b63dba9731a7e9ff87ed227 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);
        }
 }
@@ -704,6 +710,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);