diff -r 90d7364b8c9d src/login-common/login-proxy.c --- a/src/login-common/login-proxy.c Thu Apr 19 18:59:33 2012 +0300 +++ b/src/login-common/login-proxy.c Thu Apr 19 19:22:16 2012 +0300 @@ -25,6 +25,9 @@ #define KILLED_BY_ADMIN_REASON "Killed by admin" #define PROXY_IMMEDIATE_FAILURE_SECS 30 +#define PROXY_DEFAULT_TIMEOUT 5000 +#define PROXY_DEFAULT_RETRIES 10 + struct login_proxy { struct login_proxy *prev, *next; @@ -49,6 +52,8 @@ proxy_callback_t *callback; + unsigned int retries_left; + unsigned int destroying:1; unsigned int disconnecting:1; }; @@ -59,6 +64,7 @@ static struct ipc_server *login_proxy_ipc_server; static void login_proxy_ipc_cmd(struct ipc_cmd *cmd, const char *line); +static bool login_proxy_try_reconnect(struct login_proxy *proxy); static void login_proxy_free_reason(struct login_proxy **_proxy, const char *reason); @@ -196,16 +202,25 @@ static void proxy_wait_connect(struct login_proxy *proxy) { + const char *errstr; int err; err = net_geterror(proxy->server_fd); if (err != 0) { - i_error("proxy(%s): connect(%s, %u) failed: %s (after %u secs)", + errstr = t_strdup_printf( + "proxy(%s): connect(%s, %u) failed: %s " + "(after %u secs, %u retries left)", proxy->client->virtual_user, proxy->host, proxy->port, strerror(err), - (unsigned int)(ioloop_time - proxy->created.tv_sec)); + (unsigned int)(ioloop_time - proxy->created.tv_sec), + proxy->retries_left); + if (proxy->retries_left > 0) + i_warning("%s", errstr); + else + i_error("%s", errstr); proxy_fail_connect(proxy); - login_proxy_free(&proxy); + if (!login_proxy_try_reconnect(proxy)) + login_proxy_free(&proxy); return; } proxy->state_rec->last_success = ioloop_timeval; @@ -229,10 +244,20 @@ static void proxy_connect_timeout(struct login_proxy *proxy) { - i_error("proxy(%s): connect(%s, %u) timed out", - proxy->client->virtual_user, proxy->host, proxy->port); + const char *errstr; + + errstr = t_strdup_printf( + "proxy(%s): connect(%s, %u) timed out (%u retries left)", + proxy->client->virtual_user, proxy->host, proxy->port, + proxy->retries_left); + if (proxy->retries_left > 0) + i_warning("%s", errstr); + else + i_error("%s", errstr); + proxy_fail_connect(proxy); - login_proxy_free(&proxy); + if (!login_proxy_try_reconnect(proxy)) + login_proxy_free(&proxy); } static int login_proxy_connect(struct login_proxy *proxy) @@ -259,6 +284,8 @@ } proxy->server_io = io_add(proxy->server_fd, IO_WRITE, proxy_wait_connect, proxy); + if (proxy->connect_timeout_msecs == 0) + proxy->connect_timeout_msecs = PROXY_DEFAULT_TIMEOUT; if (proxy->connect_timeout_msecs != 0) { proxy->to = timeout_add(proxy->connect_timeout_msecs, proxy_connect_timeout, proxy); @@ -313,6 +340,7 @@ proxy->connect_timeout_msecs = set->connect_timeout_msecs; proxy->notify_refresh_secs = set->notify_refresh_secs; proxy->ssl_flags = set->ssl_flags; + proxy->retries_left = PROXY_DEFAULT_RETRIES; client_ref(client); memset(&dns_lookup_set, 0, sizeof(dns_lookup_set)); @@ -335,19 +363,8 @@ return 0; } -static void -login_proxy_free_reason(struct login_proxy **_proxy, const char *reason) +static void login_proxy_disconnect(struct login_proxy *proxy) { - struct login_proxy *proxy = *_proxy; - struct client *client = proxy->client; - const char *ipstr; - - *_proxy = NULL; - - if (proxy->destroying) - return; - proxy->destroying = TRUE; - if (proxy->to != NULL) timeout_remove(&proxy->to); if (proxy->to_notify != NULL) @@ -365,8 +382,54 @@ if (proxy->server_output != NULL) o_stream_destroy(&proxy->server_output); + if (proxy->ssl_server_proxy != NULL) + ssl_proxy_free(&proxy->ssl_server_proxy); + if (proxy->server_fd != -1) { + net_disconnect(proxy->server_fd); + proxy->server_fd = -1; + } + if (proxy->client_fd != -1) { /* detached proxy */ + if (proxy->client_io != NULL) + io_remove(&proxy->client_io); + if (proxy->client_output != NULL) + o_stream_destroy(&proxy->client_output); + net_disconnect(proxy->client_fd); + proxy->client_fd = -1; + } +} + +static bool login_proxy_try_reconnect(struct login_proxy *proxy) +{ + i_assert(proxy->client_fd == -1); + + if (proxy->retries_left == 0) + return FALSE; + proxy->retries_left--; + + login_proxy_disconnect(proxy); + return login_proxy_connect(proxy) == 0; +} + +static void +login_proxy_free_reason(struct login_proxy **_proxy, const char *reason) +{ + struct login_proxy *proxy = *_proxy; + struct client *client = proxy->client; + const char *ipstr; + bool detached = proxy->client_fd != -1; + + *_proxy = NULL; + + if (proxy->destroying) + return; + proxy->destroying = TRUE; + + login_proxy_disconnect(proxy); + + if (detached) { + /* detached proxy */ DLLIST_REMOVE(&login_proxies, proxy); ipstr = net_ip2addr(&proxy->client->ip); @@ -375,12 +438,6 @@ proxy->client->virtual_user, ipstr != NULL ? ipstr : "", reason == NULL ? "" : t_strdup_printf(" (%s)", reason))); - - if (proxy->client_io != NULL) - io_remove(&proxy->client_io); - if (proxy->client_output != NULL) - o_stream_destroy(&proxy->client_output); - net_disconnect(proxy->client_fd); } else { i_assert(proxy->client_io == NULL); i_assert(proxy->client_output == NULL); @@ -391,11 +448,6 @@ proxy->callback(proxy->client); } - if (proxy->server_fd != -1) - net_disconnect(proxy->server_fd); - - if (proxy->ssl_server_proxy != NULL) - ssl_proxy_free(&proxy->ssl_server_proxy); i_free(proxy->host); i_free(proxy);