]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lmtp proxy: Fixes to error handling.
authorTimo Sirainen <tss@iki.fi>
Tue, 17 Nov 2009 18:47:14 +0000 (13:47 -0500)
committerTimo Sirainen <tss@iki.fi>
Tue, 17 Nov 2009 18:47:14 +0000 (13:47 -0500)
--HG--
branch : HEAD

src/lib-lda/lmtp-client.c
src/lib-lda/lmtp-client.h
src/lmtp/lmtp-proxy.c

index 74d0bdd9c3cece845753a87a82c43d2514507404..82c6e5bf17e58dbdd699b50cdcf6ee68750255c6 100644 (file)
@@ -122,13 +122,33 @@ void lmtp_client_deinit(struct lmtp_client **_client)
        lmtp_client_unref(&client);
 }
 
-static void lmtp_client_fail(struct lmtp_client *client, const char *line)
+const char *lmtp_client_state_to_string(struct lmtp_client *client)
+{
+       switch (client->input_state) {
+       case LMTP_INPUT_STATE_GREET:
+               return "greeting";
+       case LMTP_INPUT_STATE_LHLO:
+               return "LHLO";
+       case LMTP_INPUT_STATE_MAIL_FROM:
+               return "MAIL FROM";
+       case LMTP_INPUT_STATE_RCPT_TO:
+               return "RCPT TO";
+       case LMTP_INPUT_STATE_DATA_CONTINUE:
+               return "DATA";
+       case LMTP_INPUT_STATE_DATA:
+               return "end-of-DATA";
+       }
+       return "??";
+}
+
+void lmtp_client_fail(struct lmtp_client *client, const char *line)
 {
        struct lmtp_rcpt *recipients;
        unsigned int i, count;
 
        client->global_fail_string = p_strdup(client->pool, line);
 
+       lmtp_client_ref(client);
        recipients = array_get_modifiable(&client->recipients, &count);
        for (i = client->rcpt_next_receive_idx; i < count; i++) {
                recipients[i].rcpt_to_callback(FALSE, line,
@@ -146,6 +166,7 @@ static void lmtp_client_fail(struct lmtp_client *client, const char *line)
        client->rcpt_next_data_idx = count;
 
        lmtp_client_close(client);
+       lmtp_client_unref(&client);
 }
 
 static void
index f16668859828d97a81cb8130f2400f447a3f155e..115c4833f95b14990cacb85b4c013420ffcb9a6e 100644 (file)
@@ -36,5 +36,10 @@ void lmtp_client_send(struct lmtp_client *client, struct istream *data_input);
 /* Call this function whenever input stream can potentially be read forward.
    This is useful with non-blocking istreams and tee-istreams. */
 void lmtp_client_send_more(struct lmtp_client *client);
+/* Fail the connection with line as the reply to unfinished RCPT TO/DATA
+   replies. */
+void lmtp_client_fail(struct lmtp_client *client, const char *line);
+/* Return the state (command reply) the client is currently waiting for. */
+const char *lmtp_client_state_to_string(struct lmtp_client *client);
 
 #endif
index 105bcaf7d966bb0abc29df8dfbfe76a99436aee5..553b5931c1934b1ff815dfe8f2f55a29428a2ac6 100644 (file)
@@ -197,34 +197,44 @@ static void lmtp_proxy_try_finish(struct lmtp_proxy *proxy)
                lmtp_proxy_finish(proxy);
 }
 
-static void lmtp_proxy_fail_all(struct lmtp_proxy *proxy, const char *line)
+static void lmtp_proxy_fail_all(struct lmtp_proxy *proxy, const char *reason)
 {
-       struct lmtp_proxy_recipient *rcpt;
+       struct lmtp_proxy_connection *const *conns;
        unsigned int i, count;
-       bool ret;
+       const char *line;
 
-       rcpt = array_get_modifiable(&proxy->rcpt_to, &count);
-       for (i = proxy->rcpt_next_reply_idx; i < count; i++) {
-               if (!rcpt[i].rcpt_to_failed) {
-                       i_assert(!rcpt[i].data_reply_received);
-                       rcpt[i].reply = line;
-                       rcpt[i].data_reply_received = TRUE;
+       pool_ref(proxy->pool);
+       conns = array_get(&proxy->connections, &count);
+       for (i = 0; i < count; i++) {
+               line = t_strdup_printf(ERRSTR_TEMP_REMOTE_FAILURE
+                               " (%s while waiting for reply to %s)", reason,
+                               lmtp_client_state_to_string(conns[i]->client));
+               lmtp_client_fail(conns[i]->client, line);
+
+               if (!array_is_created(&proxy->connections)) {
+                       pool_unref(&proxy->pool);
+                       return;
                }
        }
-       ret = lmtp_proxy_send_replies(proxy);
-       i_assert(ret);
-
-       lmtp_proxy_finish(proxy);
+       i_unreached();
 }
 
 static void lmtp_proxy_data_input_timeout(struct lmtp_proxy *proxy)
 {
-       lmtp_proxy_fail_all(proxy, "451 4.4.2 Input timeout in DATA");
-}
+       struct lmtp_proxy_connection *const *conns;
+       unsigned int i, count;
 
-static void lmtp_proxy_data_disconnected(struct lmtp_proxy *proxy)
-{
-       lmtp_proxy_fail_all(proxy, "451 4.4.2 Client disconnected in DATA");
+       pool_ref(proxy->pool);
+       conns = array_get(&proxy->connections, &count);
+       for (i = 0; i < count; i++) {
+               lmtp_client_fail(conns[i]->client, ERRSTR_TEMP_REMOTE_FAILURE
+                                " (timeout in DATA input)");
+               if (!array_is_created(&proxy->connections)) {
+                       pool_unref(&proxy->pool);
+                       return;
+               }
+       }
+       i_unreached();
 }
 
 static void
@@ -332,18 +342,6 @@ static bool lmtp_proxy_disconnect_hanging_output(struct lmtp_proxy *proxy)
        return TRUE;
 }
 
-static void lmtp_proxy_disconnect_unfinished(struct lmtp_proxy *proxy)
-{
-       struct lmtp_proxy_connection *const *conns;
-       unsigned int i, count;
-
-       conns = array_get(&proxy->connections, &count);
-       for (i = 0; i < count; i++) {
-               lmtp_client_fail(conns[i]->client, ERRSTR_TEMP_REMOTE_FAILURE
-                                " (DATA input timeout)");
-       }
-}
-
 static void lmtp_proxy_output_timeout(struct lmtp_proxy *proxy)
 {
        timeout_remove(&proxy->to);
@@ -355,8 +353,7 @@ static void lmtp_proxy_output_timeout(struct lmtp_proxy *proxy)
                /* no such connection, so we've already sent everything but
                   some servers aren't replying to us. disconnect all of
                   them. */
-               lmtp_proxy_disconnect_unfinished(proxy);
-               lmtp_proxy_try_finish(proxy);
+               lmtp_proxy_fail_all(proxy, "timeout");
        }
 }
 
@@ -366,10 +363,8 @@ static void lmtp_proxy_wait_for_output(struct lmtp_proxy *proxy)
 
        if (proxy->io != NULL)
                io_remove(&proxy->io);
-       if (array_count(&proxy->connections) > 1) {
-               proxy->to = timeout_add(proxy->max_timeout_msecs,
-                                       lmtp_proxy_output_timeout, proxy);
-       }
+       proxy->to = timeout_add(proxy->max_timeout_msecs,
+                               lmtp_proxy_output_timeout, proxy);
 }
 
 static bool lmtp_proxy_data_read(struct lmtp_proxy *proxy)
@@ -385,7 +380,7 @@ static bool lmtp_proxy_data_read(struct lmtp_proxy *proxy)
                return FALSE;
        case -1:
                if (proxy->data_input->stream_errno != 0)
-                       lmtp_proxy_data_disconnected(proxy);
+                       lmtp_proxy_fail_all(proxy, "disconnect");
                else {
                        /* finished reading data input. now we'll just have to
                           wait for replies. */