]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-smtp: client: transaction: Add option to submit commands immediately, rather...
authorStephan Bosch <stephan.bosch@dovecot.fi>
Sun, 30 Sep 2018 22:28:06 +0000 (00:28 +0200)
committerVille Savolainen <ville.savolainen@dovecot.fi>
Tue, 12 Feb 2019 13:40:48 +0000 (15:40 +0200)
Also, allow interleaving other unrelated (non-transaction) commands. This is
made possible by not locking/plugging the command pipeline.

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

index a880f772cbf417e97cca799b207cad6f7104e403..aa61460664095ec3e8ea7f0e1f773a79fa40ad7b 100644 (file)
@@ -125,10 +125,12 @@ struct smtp_client_transaction {
        unsigned int finish_timeout_msecs;
        struct timeout *to_finish, *to_send;
 
+       bool immediate:1;
        bool sender_accepted:1;
        bool data_provided:1;
        bool reset:1;
        bool finished:1;
+       bool submitting:1;
        bool failing:1;
        bool submitted_data:1;
 };
index 42497b7c2a5db17bf6be729e548b0917f529faf0..d875277e5eabbf84f15188bf22dbef8ff56ce302 100644 (file)
@@ -595,7 +595,8 @@ smtp_client_transaction_mail_cb(const struct smtp_reply *reply,
        }
 
        /* plug command line pipeline if no RCPT commands are yet issued */
-       if (mail->next == NULL && mail->cmd_mail_from == trans->cmd_last) {
+       if (!trans->immediate && mail->next == NULL &&
+           mail->cmd_mail_from == trans->cmd_last) {
                trans->cmd_plug = trans->cmd_last =
                        smtp_client_command_plug(trans->conn, trans->cmd_last);
        }
@@ -692,6 +693,13 @@ void smtp_client_transaction_start(
        trans->state = SMTP_CLIENT_TRANSACTION_STATE_PENDING;
 
        smtp_client_connection_add_transaction(conn, trans);
+
+       if (trans->immediate) {
+               trans->state = SMTP_CLIENT_TRANSACTION_STATE_MAIL_FROM;
+
+               if (!trans->submitting)
+                       smtp_client_transaction_submit_more(trans);
+       }
 }
 
 #undef smtp_client_transaction_start_empty
@@ -724,8 +732,8 @@ smtp_client_transaction_rcpt_cb(const struct smtp_reply *reply,
        rcpt->rcpt_callback = NULL;
 
        /* plug command line pipeline if DATA command is not yet issued */
-       if (!trans->reset && rcpt->cmd_rcpt_to == trans->cmd_last &&
-               trans->cmd_data == NULL) {
+       if (!trans->immediate && !trans->reset &&
+           rcpt->cmd_rcpt_to == trans->cmd_last && trans->cmd_data == NULL) {
                trans->cmd_plug = trans->cmd_last =
                        smtp_client_command_plug(trans->conn, trans->cmd_last);
        }
@@ -840,8 +848,8 @@ smtp_client_transaction_send_data(struct smtp_client_transaction *trans)
                        smtp_client_transaction_data_cb, trans);
                trans->submitted_data = TRUE;
 
-               i_assert(trans->cmd_last != NULL);
-               smtp_client_command_unlock(trans->cmd_last);
+               if (trans->cmd_last != NULL)
+                       smtp_client_command_unlock(trans->cmd_last);
 
                smtp_client_transaction_try_complete(trans);
        }
@@ -919,8 +927,8 @@ smtp_client_transaction_send_reset(struct smtp_client_transaction *trans)
                trans->conn, 0, trans->cmd_last,
                smtp_client_transaction_rset_cb, trans);
 
-       i_assert(trans->cmd_last != NULL);
-       smtp_client_command_unlock(trans->cmd_last);
+       if (trans->cmd_last != NULL)
+               smtp_client_command_unlock(trans->cmd_last);
 
        smtp_client_transaction_try_complete(trans);
 
@@ -955,10 +963,13 @@ void smtp_client_transaction_reset(
 }
 
 static void
-smtp_client_transaction_submit_more(struct smtp_client_transaction *trans)
+smtp_client_transaction_do_submit_more(struct smtp_client_transaction *trans)
 {
        timeout_remove(&trans->to_send);
 
+       if (trans->immediate)
+               trans->cmd_last = NULL;
+
        /* Check whether we already failed */
        if (trans->failure == NULL &&
            trans->state > SMTP_CLIENT_TRANSACTION_STATE_MAIL_FROM)
@@ -1003,7 +1014,9 @@ smtp_client_transaction_submit_more(struct smtp_client_transaction *trans)
                                        mail->mail_from, &mail->mail_params,
                                        smtp_client_transaction_mail_cb, trans);
                }
-               smtp_client_command_lock(trans->cmd_last);
+
+               if (!trans->immediate)
+                       smtp_client_command_lock(trans->cmd_last);
        }
 
        /* RCPT */
@@ -1024,10 +1037,12 @@ smtp_client_transaction_submit_more(struct smtp_client_transaction *trans)
                                        rcpt->rcpt_to, &rcpt->rcpt_params,
                                        smtp_client_transaction_rcpt_cb, rcpt);
                }
-               smtp_client_command_lock(trans->cmd_last);
+               if (!trans->immediate)
+                       smtp_client_command_lock(trans->cmd_last);
        }
 
-       if (trans->cmd_plug != NULL && trans->cmd_last != trans->cmd_plug)
+       if (trans->cmd_plug != NULL &&
+           (trans->immediate || trans->cmd_last != trans->cmd_plug))
                smtp_client_command_abort(&trans->cmd_plug);
 
        /* DATA / RSET */
@@ -1038,6 +1053,16 @@ smtp_client_transaction_submit_more(struct smtp_client_transaction *trans)
        }
 }
 
+static void
+smtp_client_transaction_submit_more(struct smtp_client_transaction *trans)
+{
+       smtp_client_transaction_ref(trans);
+       trans->submitting = TRUE;
+       smtp_client_transaction_do_submit_more(trans);
+       trans->submitting = FALSE;
+       smtp_client_transaction_unref(&trans);
+}
+
 static void
 smtp_client_transaction_submit(struct smtp_client_transaction *trans,
                               bool start)
@@ -1047,6 +1072,20 @@ smtp_client_transaction_submit(struct smtp_client_transaction *trans,
                /* Cannot submit commands at this time */
                return;
        }
+
+       if (trans->immediate) {
+               /* Submit immediately if not failed already: avoid calling
+                  failure callbacks directly (which is the first thing
+                  smtp_client_transaction_submit_more() would do). */
+               if (trans->failure == NULL &&
+                   trans->state > SMTP_CLIENT_TRANSACTION_STATE_MAIL_FROM)
+                       trans->failure = trans->mail_failure;
+               if (trans->failure == NULL) {
+                       smtp_client_transaction_submit_more(trans);
+                       return;
+               }
+       }
+
        if (trans->to_send != NULL) {
                /* Already scheduled command submission */
                return;
@@ -1115,6 +1154,12 @@ smtp_client_transaction_try_complete(struct smtp_client_transaction *trans)
        smtp_client_connection_next_transaction(trans->conn, trans);
 }
 
+void smtp_client_transaction_set_immediate(
+       struct smtp_client_transaction *trans, bool immediate)
+{
+       trans->immediate = immediate;
+}
+
 void smtp_client_transaction_connection_result(
        struct smtp_client_transaction *trans,
        const struct smtp_reply *reply)
index 811b8420d41c219fd927576a923fcc5445c50162..dc92989d82df32efb76e42afa362d0956c412c38 100644 (file)
@@ -188,6 +188,12 @@ void smtp_client_transaction_reset(
                reset_context + CALLBACK_TYPECHECK(reset_callback, void (*)( \
                        const struct smtp_reply *reply, typeof(reset_context))))
 
+/* Enables mode in which all commands are submitted immediately and (non-
+   transaction) commands can be interleaved. This is mainly important for
+   relaying SMTP in realtime. */
+void smtp_client_transaction_set_immediate(
+       struct smtp_client_transaction *trans, bool immediate);
+
 /* Return transaction statistics. */
 const struct smtp_client_transaction_times *
 smtp_client_transaction_get_times(struct smtp_client_transaction *trans);