From: Stephan Bosch Date: Wed, 21 Apr 2021 01:02:38 +0000 (+0200) Subject: lib-smtp: smtp-client-transaction - Allow destroying connection while transaction... X-Git-Tag: 2.3.16~114 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a2ea45e54305e2c39620cf26eb5ba7ea5050e1b3;p=thirdparty%2Fdovecot%2Fcore.git lib-smtp: smtp-client-transaction - Allow destroying connection while transaction still holds reference. 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) --- diff --git a/src/lib-smtp/smtp-client-connection.c b/src/lib-smtp/smtp-client-connection.c index c273630f4a..d657b83aa0 100644 --- a/src/lib-smtp/smtp-client-connection.c +++ b/src/lib-smtp/smtp-client-connection.c @@ -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); diff --git a/src/lib-smtp/smtp-client-private.h b/src/lib-smtp/smtp-client-private.h index 2cac23636a..39bbe759e4 100644 --- a/src/lib-smtp/smtp-client-private.h +++ b/src/lib-smtp/smtp-client-private.h @@ -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); diff --git a/src/lib-smtp/smtp-client-transaction.c b/src/lib-smtp/smtp-client-transaction.c index be1750825d..075d8a9b42 100644 --- a/src/lib-smtp/smtp-client-transaction.c +++ b/src/lib-smtp/smtp-client-transaction.c @@ -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: