From: Timo Sirainen Date: Mon, 23 Nov 2009 23:19:01 +0000 (-0500) Subject: lmtp: Error handling fixes. X-Git-Tag: 2.0.beta1~83 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=facb2d5c0fbf4a773ad7f7f57bfded5d0ba6f1f9;p=thirdparty%2Fdovecot%2Fcore.git lmtp: Error handling fixes. --HG-- branch : HEAD --- diff --git a/src/lib-lda/lmtp-client.c b/src/lib-lda/lmtp-client.c index 3ac4d300ec..01ee4167e5 100644 --- a/src/lib-lda/lmtp-client.c +++ b/src/lib-lda/lmtp-client.c @@ -502,9 +502,14 @@ void lmtp_client_add_rcpt(struct lmtp_client *client, const char *address, rcpt->data_callback = data_callback; rcpt->context = context; - if (client->global_fail_string != NULL) + if (client->global_fail_string != NULL) { + client->rcpt_next_receive_idx++; + i_assert(client->rcpt_next_receive_idx == + array_count(&client->recipients)); + + rcpt->failed = TRUE; rcpt_to_callback(FALSE, client->global_fail_string, context); - else if (client->input_state == LMTP_INPUT_STATE_RCPT_TO) + } else if (client->input_state == LMTP_INPUT_STATE_RCPT_TO) lmtp_client_send_rcpts(client); } @@ -516,6 +521,11 @@ void lmtp_client_send(struct lmtp_client *client, struct istream *data_input) lmtp_client_send_data_cmd(client); } +bool lmtp_client_is_data_input_finished(struct lmtp_client *client) +{ + return client->data_input != NULL; +} + void lmtp_client_send_more(struct lmtp_client *client) { if (client->input_state == LMTP_INPUT_STATE_DATA) diff --git a/src/lib-lda/lmtp-client.h b/src/lib-lda/lmtp-client.h index 115c4833f9..2b9b1e8ccb 100644 --- a/src/lib-lda/lmtp-client.h +++ b/src/lib-lda/lmtp-client.h @@ -33,6 +33,8 @@ void lmtp_client_add_rcpt(struct lmtp_client *client, const char *address, lmtp_callback_t *data_callback, void *context); /* Start sending input stream as DATA. */ void lmtp_client_send(struct lmtp_client *client, struct istream *data_input); +/* Returns TRUE if data_input is no longer needed. */ +bool lmtp_client_is_data_input_finished(struct lmtp_client *client); /* 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); diff --git a/src/lmtp/lmtp-proxy.c b/src/lmtp/lmtp-proxy.c index 4b62aea749..4876b01675 100644 --- a/src/lmtp/lmtp-proxy.c +++ b/src/lmtp/lmtp-proxy.c @@ -55,8 +55,6 @@ struct lmtp_proxy { unsigned int finished:1; }; -static void lmtp_proxy_conn_deinit(struct lmtp_proxy_connection *conn, - const char *reason); static void lmtp_proxy_data_input(struct lmtp_proxy *proxy); struct lmtp_proxy * @@ -84,7 +82,7 @@ static void lmtp_proxy_connections_deinit(struct lmtp_proxy *proxy) conns = array_get(&proxy->connections, &count); for (i = 0; i < count; i++) - lmtp_proxy_conn_deinit(conns[i], "451 4.3.0 Aborting"); + lmtp_client_fail(conns[i]->client, "451 4.3.0 Aborting"); } void lmtp_proxy_deinit(struct lmtp_proxy **_proxy) @@ -146,22 +144,12 @@ lmtp_proxy_get_connection(struct lmtp_proxy *proxy, return conn; } -static void lmtp_proxy_conn_deinit(struct lmtp_proxy_connection *conn, - const char *reason) +static void lmtp_proxy_conn_close(struct lmtp_proxy_connection *conn) { - struct lmtp_proxy_recipient *rcpt; - - /* set failure replies to all recipients in this connection */ - array_foreach_modifiable(&conn->proxy->rcpt_to, rcpt) { - if (rcpt->conn == conn && !rcpt->rcpt_to_failed) - rcpt->reply = reason; - } - if (conn->client != NULL) lmtp_client_deinit(&conn->client); if (conn->data_input != NULL) i_stream_unref(&conn->data_input); - conn->failed = TRUE; } static bool lmtp_proxy_send_replies(struct lmtp_proxy *proxy) @@ -256,6 +244,10 @@ lmtp_proxy_conn_rcpt_to(bool success, const char *reply, void *context) } i_assert(i != count); + if (!success && conn->rcpt_next_reply_low_idx == count && + lmtp_client_is_data_input_finished(conn->client)) + lmtp_proxy_conn_close(conn); + /* send replies only if we've already sent DATA. */ if (conn->proxy->data_input != NULL) lmtp_proxy_try_finish(conn->proxy); @@ -281,6 +273,11 @@ lmtp_proxy_conn_data(bool success ATTR_UNUSED, const char *reply, void *context) } } i_assert(i != count); + + if (conn->data_next_reply_low_idx == count && + lmtp_client_is_data_input_finished(conn->client)) + lmtp_proxy_conn_close(conn); + lmtp_proxy_try_finish(conn->proxy); } @@ -334,9 +331,9 @@ static bool lmtp_proxy_disconnect_hanging_output(struct lmtp_proxy *proxy) for (i = 0; i < count; i++) { (void)i_stream_get_data(conns[i]->data_input, &size); if (size == max_size) { - lmtp_proxy_conn_deinit(conns[i], - ERRSTR_TEMP_REMOTE_FAILURE - " (DATA output timeout)"); + lmtp_client_fail(conns[i]->client, + ERRSTR_TEMP_REMOTE_FAILURE + " (DATA output timeout)"); } } return TRUE;