lmtp-proxy.c revision 183bea41fa640dc8117f3eb45ff935cd81377a84
/* Copyright (c) 2009-2011 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "ioloop.h"
#include "istream.h"
#include "istream-tee.h"
#include "ostream.h"
#include "lmtp-client.h"
#include "lmtp-proxy.h"
#define LMTP_MAX_LINE_LEN 1024
struct lmtp_proxy_recipient {
struct lmtp_proxy_connection *conn;
const char *address;
const char *reply;
unsigned int rcpt_to_failed:1;
unsigned int data_reply_received:1;
};
struct lmtp_proxy_connection {
struct lmtp_proxy *proxy;
struct lmtp_proxy_settings set;
struct lmtp_client *client;
struct istream *data_input;
unsigned int finished:1;
unsigned int failed:1;
};
struct lmtp_proxy {
const char *mail_from, *my_hostname;
const char *dns_client_socket_path;
unsigned int next_data_reply_idx;
struct ostream *client_output;
struct tee_istream *tee_data_input;
unsigned int max_timeout_msecs;
void *finish_context;
unsigned int finished:1;
unsigned int input_timeout:1;
unsigned int handling_data_input:1;
};
static void lmtp_conn_finish(void *context);
struct lmtp_proxy *
struct ostream *client_output)
{
struct lmtp_proxy *proxy;
return proxy;
}
{
struct lmtp_proxy_connection *const *conns;
}
}
{
}
{
}
static struct lmtp_proxy_connection *
const struct lmtp_proxy_settings *set)
{
struct lmtp_client_settings client_set;
return conn;
}
return conn;
}
{
struct lmtp_proxy_recipient *const *rcpt;
unsigned int i, count;
break;
}
proxy->next_data_reply_idx = i;
return i == count;
}
{
}
{
/* do the actual finishing in a timeout handler, since the finish
callback causes the proxy to be destroyed and the code leading up
to this function can be called from many different places. it's
easier this way rather than having all the callers check if the
proxy was already destroyed. */
proxy);
}
}
{
/* DATA command hasn't been sent yet */
return;
}
if (lmtp_proxy_send_data_replies(proxy) &&
}
static void lmtp_conn_finish(void *context)
{
}
{
struct lmtp_proxy_connection *const *conns;
unsigned int i, count;
const char *line;
for (i = 0; i < count; i++) {
" (%s while waiting for reply to %s)", reason,
}
/* we still have some DATA input to read */
}
}
}
{
struct lmtp_proxy_connection *const *conns;
unsigned int i, count;
for (i = 0; i < count; i++) {
" (timeout in DATA input)");
}
/* we had earlier failed all clients already and were just
waiting for DATA input to finish, but DATA input also failed
with a timeout. */
}
}
static void
{
}
static void
{
}
const struct lmtp_proxy_settings *set)
{
struct lmtp_proxy_connection *conn;
struct lmtp_proxy_recipient *rcpt;
return -1;
return 0;
}
{
struct lmtp_proxy_connection *const *conns;
}
return min_offset;
}
{
struct lmtp_proxy_connection *const *conns;
return FALSE;
/* disconnect all connections that are keeping us from reading
more input. */
" (DATA output timeout)");
}
}
return TRUE;
}
{
/* drop the connection with the most unread data */
else {
/* no such connection, so we've already sent everything but
some servers aren't replying to us. disconnect all of
them. */
}
}
{
}
}
{
struct lmtp_proxy_connection *const *conns;
}
{
case 0:
/* nothing new read */
return FALSE;
return FALSE;
}
/* fall through */
case -2:
/* buffer full. someone's stalling. */
return FALSE;
case -1:
else {
/* make sure LMTP clients see the EOF */
/* finished reading data input. now we'll just have to
wait for replies. */
/* if all RCPT TOs failed, we can finish now */
}
return FALSE;
default:
/* something was read */
return TRUE;
}
}
{
do {
} while (lmtp_proxy_data_read(proxy));
}
static void lmtp_proxy_more_data_sent(void *context)
{
/* some tee child is blocking others. it might have been this
one, so see if we can continue. */
}
}
const char *header,
{
struct lmtp_proxy_connection *const *conns;
/* this connection had already failed */
continue;
}
proxy);
conn->data_input =
}
}