r15238: Add some code to automatically reconnect if we want to.
authorSimo Sorce <idra@samba.org>
Tue, 25 Apr 2006 11:50:32 +0000 (11:50 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 19:04:23 +0000 (14:04 -0500)
(This used to be commit e2102999e26566543162455b34adbd2b0486b74d)

source4/libcli/ldap/ldap_bind.c
source4/libcli/ldap/ldap_client.c
source4/libcli/ldap/ldap_client.h

index 585bdbb2343d9bb7a7a64143066ca8e89c735b30..c33d53f775751c2396cb52cf62d523ddd6f2b05e 100644 (file)
 #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:
index 364961cf47010c5a2dd212b982211bb270b3be3b..344605f4ec83a28b3462fb382b97f32c94a45e9c 100644 (file)
@@ -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;
                }
index 3f71c42f226a90d45d356d22c4c1718affc436bc..7801f8b6bc5ea17eb835e430055a458c60f9bbe5 100644 (file)
@@ -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;