From 8f164299473553ee28f4fbf1d9a120840c5e5feb Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Tue, 25 Apr 2006 11:50:32 +0000 Subject: r15238: Add some code to automatically reconnect if we want to. (This used to be commit e2102999e26566543162455b34adbd2b0486b74d) --- source4/libcli/ldap/ldap_bind.c | 53 ++++++++++++++++++++++++++ source4/libcli/ldap/ldap_client.c | 78 ++++++++++++++++++++++++++++++++++----- source4/libcli/ldap/ldap_client.h | 14 ++++++- 3 files changed, 134 insertions(+), 11 deletions(-) diff --git a/source4/libcli/ldap/ldap_bind.c b/source4/libcli/ldap/ldap_bind.c index 585bdbb234..c33d53f775 100644 --- a/source4/libcli/ldap/ldap_bind.c +++ b/source4/libcli/ldap/ldap_bind.c @@ -28,6 +28,39 @@ #include "lib/tls/tls.h" #include "auth/auth.h" +struct ldap_simple_creds { + const char *dn; + const char *pw; +}; + +NTSTATUS ldap_rebind(struct ldap_connection *conn) +{ + NTSTATUS status; + struct ldap_simple_creds *creds; + + switch (conn->bind.type) { + case LDAP_BIND_SASL: + status = ldap_bind_sasl(conn, (struct cli_credentials *)conn->bind.creds); + break; + + case LDAP_BIND_SIMPLE: + creds = (struct ldap_simple_creds *)conn->bind.creds; + + if (creds == NULL) { + return NT_STATUS_UNSUCCESSFUL; + } + + status = ldap_bind_simple(conn, creds->dn, creds->pw); + break; + + default: + return NT_STATUS_UNSUCCESSFUL; + } + + return status; +} + + static struct ldap_message *new_ldap_simple_bind_msg(struct ldap_connection *conn, const char *dn, const char *pw) { @@ -110,6 +143,20 @@ NTSTATUS ldap_bind_simple(struct ldap_connection *conn, talloc_free(req); + if (NT_STATUS_IS_OK(status)) { + struct ldap_simple_creds *creds = talloc(conn, struct ldap_simple_creds); + if (creds == NULL) { + return NT_STATUS_NO_MEMORY; + } + creds->dn = talloc_strdup(creds, dn); + creds->pw = talloc_strdup(creds, pw); + if (creds->dn == NULL || creds->pw == NULL) { + return NT_STATUS_NO_MEMORY; + } + conn->bind.type = LDAP_BIND_SIMPLE; + conn->bind.creds = creds; + } + return status; } @@ -325,6 +372,12 @@ NTSTATUS ldap_bind_sasl(struct ldap_connection *conn, struct cli_credentials *cr } talloc_free(tmp_ctx); + + if (NT_STATUS_IS_OK(status)) { + conn->bind.type = LDAP_BIND_SASL; + conn->bind.creds = creds; + } + return status; failed: diff --git a/source4/libcli/ldap/ldap_client.c b/source4/libcli/ldap/ldap_client.c index 364961cf47..344605f4ec 100644 --- a/source4/libcli/ldap/ldap_client.c +++ b/source4/libcli/ldap/ldap_client.c @@ -33,6 +33,7 @@ #include "libcli/composite/composite.h" #include "lib/stream/packet.h" #include "auth/gensec/gensec.h" +#include "system/time.h" /* @@ -62,10 +63,12 @@ struct ldap_connection *ldap_new_connection(TALLOC_CTX *mem_ctx, /* set a reasonable request timeout */ conn->timeout = 60; + /* explicitly avoid reconnections by default */ + conn->reconnect.max_retries = 0; + return conn; } - /* the connection is dead */ @@ -73,6 +76,7 @@ static void ldap_connection_dead(struct ldap_connection *conn) { struct ldap_request *req; + /* return an error for any pending request ... */ while (conn->pending) { req = conn->pending; DLIST_REMOVE(req->conn->pending, req); @@ -84,9 +88,16 @@ static void ldap_connection_dead(struct ldap_connection *conn) } talloc_free(conn->tls); + talloc_free(conn->sock); /* this will also free event.fde */ + talloc_free(conn->packet); conn->tls = NULL; + conn->sock = NULL; + conn->event.fde = NULL; + conn->packet = NULL; } +static void ldap_reconnect(struct ldap_connection *conn); + /* handle packet errors */ @@ -95,6 +106,9 @@ static void ldap_error_handler(void *private_data, NTSTATUS status) struct ldap_connection *conn = talloc_get_type(private_data, struct ldap_connection); ldap_connection_dead(conn); + + /* but try to reconnect so that the ldb client can go on */ + ldap_reconnect(conn); } @@ -325,6 +339,11 @@ struct composite_context *ldap_connect_send(struct ldap_connection *conn, struct composite_context *result, *ctx; struct ldap_connect_state *state; + if (conn->reconnect.url == NULL) { + conn->reconnect.url = talloc_strdup(conn, url); + if (conn->reconnect.url == NULL) goto failed; + } + result = talloc_zero(NULL, struct composite_context); if (result == NULL) goto failed; result->state = COMPOSITE_STATE_IN_PROGRESS; @@ -419,6 +438,40 @@ NTSTATUS ldap_connect(struct ldap_connection *conn, const char *url) return ldap_connect_recv(ctx); } +/* Actually this function is NOT ASYNC safe, FIXME? */ +static void ldap_reconnect(struct ldap_connection *conn) +{ + NTSTATUS status; + time_t now = time(NULL); + + /* do we have set up reconnect ? */ + if (conn->reconnect.max_retries == 0) return; + + /* is the retry time expired ? */ + if (now > conn->reconnect.previous + 30) { + conn->reconnect.retries = 0; + conn->reconnect.previous = now; + } + + /* are we reconnectind too often and too fast? */ + if (conn->reconnect.retries > conn->reconnect.max_retries) return; + + /* keep track of the number of reconnections */ + conn->reconnect.retries++; + + /* reconnect */ + status = ldap_connect(conn, conn->reconnect.url); + if ( ! NT_STATUS_IS_OK(status)) { + return; + } + + /* rebind */ + status = ldap_rebind(conn); + if ( ! NT_STATUS_IS_OK(status)) { + ldap_connection_dead(conn); + } +} + /* destroy an open ldap request */ static int ldap_request_destructor(void *ptr) { @@ -466,15 +519,16 @@ struct ldap_request *ldap_request_send(struct ldap_connection *conn, struct ldap_message *msg) { struct ldap_request *req; - NTSTATUS status; + NTSTATUS status = NT_STATUS_UNSUCCESSFUL; + + req = talloc_zero(conn, struct ldap_request); + if (req == NULL) return NULL; if (conn->tls == NULL) { - return NULL; + status = NT_STATUS_INVALID_CONNECTION; + goto failed; } - req = talloc_zero(conn, struct ldap_request); - if (req == NULL) goto failed; - req->state = LDAP_REQUEST_SEND; req->conn = conn; req->messageid = conn->next_messageid++; @@ -541,8 +595,12 @@ struct ldap_request *ldap_request_send(struct ldap_connection *conn, return req; failed: - talloc_free(req); - return NULL; + req->status = status; + req->state = LDAP_REQUEST_ERROR; + event_add_timed(conn->event.event_ctx, req, timeval_zero(), + ldap_request_complete, req); + + return req; } @@ -552,7 +610,7 @@ failed: */ NTSTATUS ldap_request_wait(struct ldap_request *req) { - while (req->state != LDAP_REQUEST_DONE) { + while (req->state <= LDAP_REQUEST_DONE) { if (event_loop_once(req->conn->event.event_ctx) != 0) { req->status = NT_STATUS_UNEXPECTED_NETWORK_ERROR; break; @@ -665,7 +723,7 @@ NTSTATUS ldap_result_n(struct ldap_request *req, int n, struct ldap_message **ms NT_STATUS_HAVE_NO_MEMORY(req); - while (req->state != LDAP_REQUEST_DONE && n >= req->num_replies) { + while (req->state <= LDAP_REQUEST_DONE && n >= req->num_replies) { if (event_loop_once(req->conn->event.event_ctx) != 0) { return NT_STATUS_UNEXPECTED_NETWORK_ERROR; } diff --git a/source4/libcli/ldap/ldap_client.h b/source4/libcli/ldap/ldap_client.h index 3f71c42f22..7801f8b6bc 100644 --- a/source4/libcli/ldap/ldap_client.h +++ b/source4/libcli/ldap/ldap_client.h @@ -23,7 +23,7 @@ #include "libcli/ldap/ldap.h" -enum ldap_request_state {LDAP_REQUEST_SEND, LDAP_REQUEST_PENDING, LDAP_REQUEST_DONE}; +enum ldap_request_state { LDAP_REQUEST_SEND=1, LDAP_REQUEST_PENDING=2, LDAP_REQUEST_DONE=3, LDAP_REQUEST_ERROR=4 }; /* this is the handle that the caller gets when an async ldap message is sent */ @@ -60,6 +60,18 @@ struct ldap_connection { const char *auth_dn; const char *simple_pw; + struct { + char *url; + int max_retries; + int retries; + time_t previous; + } reconnect; + + struct { + enum { LDAP_BIND_SIMPLE, LDAP_BIND_SASL } type; + void *creds; + } bind; + /* next message id to assign */ unsigned next_messageid; -- cgit