summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimo Sorce <idra@samba.org>2006-04-25 11:50:32 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 14:04:23 -0500
commit8f164299473553ee28f4fbf1d9a120840c5e5feb (patch)
treecf2fad51c66eeaa10375b172baa9ba31ca5665d7
parent1e8e6aeb6fed306be4196daca19af284a7fef3cf (diff)
downloadsamba-8f164299473553ee28f4fbf1d9a120840c5e5feb.tar.gz
samba-8f164299473553ee28f4fbf1d9a120840c5e5feb.tar.bz2
samba-8f164299473553ee28f4fbf1d9a120840c5e5feb.zip
r15238: Add some code to automatically reconnect if we want to.
(This used to be commit e2102999e26566543162455b34adbd2b0486b74d)
-rw-r--r--source4/libcli/ldap/ldap_bind.c53
-rw-r--r--source4/libcli/ldap/ldap_client.c78
-rw-r--r--source4/libcli/ldap/ldap_client.h14
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;