#include "ostream.h"
#include "llist.h"
#include "str-sanitize.h"
+#include "time-util.h"
#include "master-service.h"
#include "client-common.h"
#include "ssl-proxy.h"
+#include "login-proxy-state.h"
#include "login-proxy.h"
#define MAX_PROXY_INPUT_SIZE 4096
struct ip_addr ip;
struct ssl_proxy *ssl_proxy;
+ struct timeval created;
struct timeout *to;
+ struct login_proxy_record *state_rec;
char *host, *user;
unsigned int port;
unsigned int disconnecting:1;
};
+static struct login_proxy_state *proxy_state;
static struct login_proxy *login_proxies = NULL;
static void server_input(struct login_proxy *proxy)
io_add(proxy->server_fd, IO_READ, proxy_prelogin_input, proxy);
}
+static void proxy_fail_connect(struct login_proxy *proxy)
+{
+ if (timeval_cmp(&proxy->created, &proxy->state_rec->last_success) < 0) {
+ /* there was a successful connection done since we started
+ connecting. perhaps this is just a temporary one-off
+ failure. */
+ } else {
+ proxy->state_rec->last_failure = ioloop_timeval;
+ }
+ proxy->state_rec->num_waiting_connections--;
+ proxy->state_rec = NULL;
+}
+
static void proxy_wait_connect(struct login_proxy *proxy)
{
int err;
if (err != 0) {
i_error("proxy: connect(%s, %u) failed: %s",
proxy->host, proxy->port, strerror(err));
+ proxy_fail_connect(proxy);
login_proxy_free(&proxy);
return;
}
+ proxy->state_rec->last_success = ioloop_timeval;
+ proxy->state_rec->num_waiting_connections--;
+ proxy->state_rec = NULL;
if (proxy->to != NULL)
timeout_remove(&proxy->to);
static void proxy_connect_timeout(struct login_proxy *proxy)
{
i_error("proxy: connect(%s, %u) timed out", proxy->host, proxy->port);
+ proxy_fail_connect(proxy);
login_proxy_free(&proxy);
}
proxy_callback_t *callback, void *context)
{
struct login_proxy *proxy;
+ struct login_proxy_record *rec;
struct ip_addr ip;
int fd;
return NULL;
}
+ rec = login_proxy_state_get(proxy_state, &ip);
+ if (timeval_cmp(&rec->last_failure, &rec->last_success) > 0 &&
+ rec->num_waiting_connections != 0) {
+ /* the server is down. fail immediately */
+ return NULL;
+ }
+
fd = net_connect_ip(&ip, set->port, NULL);
if (fd < 0) {
i_error("proxy(%s): connect(%s, %u) failed: %m",
}
proxy = i_new(struct login_proxy, 1);
+ proxy->created = ioloop_timeval;
proxy->host = i_strdup(set->host);
proxy->user = i_strdup(client->virtual_user);
proxy->port = set->port;
proxy->ip = client->ip;
proxy->client_fd = -1;
+
+ proxy->state_rec = rec;
+ rec->num_waiting_connections++;
return proxy;
}
if (proxy->to != NULL)
timeout_remove(&proxy->to);
+ if (proxy->state_rec != NULL)
+ proxy->state_rec->num_waiting_connections--;
+ if (proxy->to != NULL)
+ timeout_remove(&proxy->to);
+
if (proxy->server_io != NULL)
io_remove(&proxy->server_io);
if (proxy->server_input != NULL)
return 0;
}
+void login_proxy_init(void)
+{
+ proxy_state = login_proxy_state_init();
+}
+
void login_proxy_deinit(void)
{
struct login_proxy *proxy;
proxy = login_proxies;
login_proxy_free(&proxy);
}
+ login_proxy_state_deinit(&proxy_state);
}