From 007ef91db133cf592c4a03843d2953c973339d5c Mon Sep 17 00:00:00 2001 From: Jiri Hruska Date: Fri, 30 Aug 2013 07:12:54 +0200 Subject: [PATCH] Implement reconnect when LDAP connection goes down --- ngx_http_auth_ldap_module.c | 55 +++++++++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/ngx_http_auth_ldap_module.c b/ngx_http_auth_ldap_module.c index f896b12..2294262 100644 --- a/ngx_http_auth_ldap_module.c +++ b/ngx_http_auth_ldap_module.c @@ -134,6 +134,7 @@ typedef struct ngx_http_auth_ldap_connection { ngx_log_t *log; ngx_http_auth_ldap_server_t *server; ngx_peer_connection_t conn; + ngx_event_t reconnect_event; ngx_queue_t queue; ngx_http_auth_ldap_ctx_t *rctx; @@ -916,23 +917,38 @@ static Sockbuf_IO ngx_http_auth_ldap_sbio = static void ngx_http_auth_ldap_close_connection(ngx_http_auth_ldap_connection_t *c) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http_auth_ldap: Closing connection"); + ngx_queue_t *q; if (c->ld) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http_auth_ldap: Unbinding from the server"); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http_auth_ldap: Unbinding from the server \"%V\")", + &c->server->url); ldap_unbind_ext(c->ld, NULL, NULL); /* Unbind is always synchronous, even though the function name does not end with an '_s'. */ c->ld = NULL; } if (c->conn.connection) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http_auth_ldap: Closing connection fd=%d", + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http_auth_ldap: Closing connection (fd=%d)", c->conn.connection->fd); ngx_close_connection(c->conn.connection); + c->conn.connection = NULL; + } + + q = ngx_queue_head(&c->server->free_connections); + while (q != ngx_queue_sentinel(&c->server->free_connections)) { + if (q == &c->queue) { + ngx_queue_remove(q); + break; + } + q = ngx_queue_next(q); } c->rctx = NULL; - c->state = STATE_DISCONNECTED; + if (c->state != STATE_DISCONNECTED) { + c->state = STATE_DISCONNECTED; + ngx_add_timer(&c->reconnect_event, 10000); /* TODO: Reconnect timeout */ + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http_auth_ldap: Connection scheduled for reconnection in 10000 ms"); + } } static void @@ -1114,6 +1130,12 @@ ngx_http_auth_ldap_read_handler(ngx_event_t *rev) conn = ((ngx_connection_t *)rev->data)->data; c = conn->data; + if (c->ld == NULL) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, "http_auth_ldap: Could not connect"); + ngx_http_auth_ldap_close_connection(c); + return; + } + if (rev->timedout) { ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "http_auth_ldap: Request timed out (state=%d)", c->state); conn->connection->timedout = 1; @@ -1237,6 +1259,9 @@ ngx_http_auth_ldap_connect(ngx_http_auth_ldap_connection_t *c) addr = &c->server->parsed_url.addrs[ngx_random() % c->server->parsed_url.naddrs]; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http_auth_ldap: Connecting to LDAP server \"%V\".", + &addr->name); + conn = &c->conn; conn->data = c; conn->sockaddr = addr->sockaddr; @@ -1251,6 +1276,7 @@ ngx_http_auth_ldap_connect(ngx_http_auth_ldap_connection_t *c) if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) { ngx_log_error(NGX_LOG_ERR, c->log, 0, "http_auth_ldap: Unable to connect to LDAP server \"%V\".", &addr->name); + ngx_add_timer(&c->reconnect_event, 10000); /* TODO: Reconnect timeout */ return; } @@ -1269,6 +1295,14 @@ ngx_http_auth_ldap_connection_cleanup(void *data) ngx_http_auth_ldap_close_connection((ngx_http_auth_ldap_connection_t *) data); } +static void +ngx_http_auth_ldap_reconnect_handler(ngx_event_t *ev) +{ + ngx_connection_t *conn = ev->data; + ngx_http_auth_ldap_connection_t *c = conn->data; + ngx_http_auth_ldap_connect(c); +} + static ngx_int_t ngx_http_auth_ldap_init_connections(ngx_cycle_t *cycle) { @@ -1276,6 +1310,7 @@ ngx_http_auth_ldap_init_connections(ngx_cycle_t *cycle) ngx_http_auth_ldap_main_conf_t *halmcf; ngx_http_auth_ldap_server_t *server; ngx_pool_cleanup_t *cleanup; + ngx_connection_t *dummy_conn; ngx_uint_t i, j; ngx_int_t rc; int option; @@ -1302,13 +1337,23 @@ ngx_http_auth_ldap_init_connections(ngx_cycle_t *cycle) for (j = 0; j < server->connections; j++) { c = ngx_pcalloc(cycle->pool, sizeof(ngx_http_auth_ldap_connection_t)); cleanup = ngx_pool_cleanup_add(cycle->pool, 0); - if (c == NULL || cleanup == NULL) { + dummy_conn = ngx_pcalloc(cycle->pool, sizeof(ngx_connection_t)); + if (c == NULL || cleanup == NULL || dummy_conn == NULL) { return NGX_ERROR; } c->log = cycle->log; c->server = server; c->state = STATE_DISCONNECTED; + + /* Various debug logging around timer management assume that the field + 'data' in ngx_event_t is a pointer to ngx_connection_t, therefore we + have a dummy such structure around so that it does not crash etc. */ + dummy_conn->data = c; + c->reconnect_event.log = c->log; + c->reconnect_event.data = dummy_conn; + c->reconnect_event.handler = ngx_http_auth_ldap_reconnect_handler; + ngx_http_auth_ldap_connect(c); cleanup->handler = &ngx_http_auth_ldap_connection_cleanup;