]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-smtp: smtp-client-transaction - Allow destroying connection while transaction...
authorStephan Bosch <stephan.bosch@open-xchange.com>
Wed, 21 Apr 2021 01:02:38 +0000 (03:02 +0200)
committeraki.tuomi <aki.tuomi@open-xchange.com>
Fri, 21 May 2021 20:20:48 +0000 (20:20 +0000)
The lifetime of the transaction is controlled by the application and not so much
by the connection. The transaction holds a reference to the connection, so if
the connection is forcibly destroyed it needs, to notify the transaction of this
event.

This fixes:

Panic: file connection.c: line 938 (connection_list_deinit): assertion failed: (conn != list->connections)

src/lib-smtp/smtp-client-connection.c
src/lib-smtp/smtp-client-private.h
src/lib-smtp/smtp-client-transaction.c

index c273630f4a607e4d2c7ef0f391cb477606072e82..d657b83aa043f7ce47485bd52fd6dfbe3a9ec396 100644 (file)
@@ -195,6 +195,19 @@ smtp_client_connection_transactions_fail(
        smtp_client_connection_transactions_fail_reply(conn, &reply);
 }
 
+static void
+smtp_client_connection_transactions_drop(struct smtp_client_connection *conn)
+{
+       struct smtp_client_transaction *trans;
+
+       trans = conn->transactions_head;
+       while (trans != NULL) {
+               struct smtp_client_transaction *trans_next = trans->next;
+               smtp_client_transaction_connection_destroyed(trans);
+               trans = trans_next;
+       }
+}
+
 static void
 smtp_client_connection_login_callback(struct smtp_client_connection *conn,
                                      const struct smtp_reply *reply)
@@ -2209,6 +2222,7 @@ void smtp_client_connection_unref(struct smtp_client_connection **_conn)
        smtp_client_connection_commands_fail(
                conn, SMTP_CLIENT_COMMAND_ERROR_ABORTED,
                "Connection destroy");
+       smtp_client_connection_transactions_drop(conn);
 
        connection_deinit(&conn->conn);
 
index 2cac23636ae7eb490d4cdbf8b84b7217db7e0734..39bbe759e461359d0a3d17449202b551a76092df 100644 (file)
@@ -290,6 +290,9 @@ void smtp_client_commands_fail_delayed(struct smtp_client_connection *conn);
 void smtp_client_transaction_connection_result(
        struct smtp_client_transaction *trans,
        const struct smtp_reply *reply);
+void smtp_client_transaction_connection_destroyed(
+       struct smtp_client_transaction *trans);
+
 void smtp_client_transaction_switch_ioloop(
        struct smtp_client_transaction *trans);
 
index be1750825db9d4cdbbfc485a0ba8ce34e40bd9b5..075d8a9b4210e3daee63fe1825f267a941d2d135 100644 (file)
@@ -789,6 +789,7 @@ void smtp_client_transaction_fail(struct smtp_client_transaction *trans,
 void smtp_client_transaction_set_event(struct smtp_client_transaction *trans,
                                       struct event *event)
 {
+       i_assert(trans->conn != NULL);
        event_unref(&trans->event);
        trans->event = event_create(event);
        event_set_forced_debug(trans->event, trans->conn->set.debug);
@@ -834,6 +835,7 @@ smtp_client_transaction_mail_cb(const struct smtp_reply *reply,
        e_debug(trans->event, "Got MAIL reply: %s", smtp_reply_log(reply));
 
        i_assert(mail != NULL);
+       i_assert(trans->conn != NULL);
 
        if (success) {
                if (trans->sender_accepted) {
@@ -938,6 +940,7 @@ void smtp_client_transaction_start(
        struct smtp_client_transaction_mail *mail = trans->mail_head;
 
        i_assert(trans->state == SMTP_CLIENT_TRANSACTION_STATE_NEW);
+       i_assert(trans->conn != NULL);
 
        i_assert(mail != NULL);
        event_add_str(trans->event, "mail_from",
@@ -993,6 +996,8 @@ smtp_client_transaction_rcpt_cb(const struct smtp_reply *reply,
 {
        struct smtp_client_transaction *trans = rcpt->trans;
 
+       i_assert(trans->conn != NULL);
+
        e_debug(trans->event, "Got RCPT reply: %s", smtp_reply_log(reply));
 
        /* plug command line pipeline if DATA command is not yet issued */
@@ -1173,6 +1178,8 @@ smtp_client_transaction_send_data(struct smtp_client_transaction *trans)
                }
                i_assert(failure.status != 0);
        } else {
+               i_assert(trans->conn != NULL);
+
                trans->cmd_data = smtp_client_command_data_submit_after(
                        trans->conn, 0, trans->cmd_last, trans->data_input,
                        smtp_client_transaction_data_cb, trans);
@@ -1258,6 +1265,8 @@ smtp_client_transaction_send_reset(struct smtp_client_transaction *trans)
                failure = *trans->failure;
                i_assert(failure.status != 0);
        } else {
+               i_assert(trans->conn != NULL);
+
                trans->cmd_rset = smtp_client_command_rset_submit_after(
                        trans->conn, 0, trans->cmd_last,
                        smtp_client_transaction_rset_cb, trans);
@@ -1318,6 +1327,8 @@ smtp_client_transaction_do_submit_more(struct smtp_client_transaction *trans)
                return;
        }
 
+       i_assert(trans->conn != NULL);
+
        /* Make sure transaction is started */
        if (trans->state == SMTP_CLIENT_TRANSACTION_STATE_NEW) {
                enum smtp_client_transaction_state state;
@@ -1437,6 +1448,8 @@ smtp_client_transaction_submit(struct smtp_client_transaction *trans,
 static void
 smtp_client_transaction_try_complete(struct smtp_client_transaction *trans)
 {
+       i_assert(trans->conn != NULL);
+
        if (trans->rcpts_queue_count > 0) {
                /* Not all RCPT replies have come in yet */
                e_debug(trans->event,  "RCPT replies are still pending (%u/%u)",
@@ -1514,6 +1527,13 @@ void smtp_client_transaction_connection_result(
        smtp_client_transaction_connection_ready(trans);
 }
 
+void smtp_client_transaction_connection_destroyed(
+       struct smtp_client_transaction *trans)
+{
+       i_assert(trans->failure != NULL);
+       smtp_client_connection_unref(&trans->conn);
+}
+
 const struct smtp_client_transaction_times *
 smtp_client_transaction_get_times(struct smtp_client_transaction *trans)
 {
@@ -1544,6 +1564,7 @@ smtp_client_transaction_get_state_destription(
        case SMTP_CLIENT_TRANSACTION_STATE_NEW:
                break;
        case SMTP_CLIENT_TRANSACTION_STATE_PENDING:
+               i_assert(trans->conn != NULL);
                conn_state = smtp_client_connection_get_state(trans->conn);
                switch (conn_state) {
                case SMTP_CLIENT_CONNECTION_STATE_CONNECTING: