changeset 6368:a930c2ecd73c HEAD

Reconnect if ldap_search() returns a failure related to connection problems. Also if ldap_result() doesn't return a connection related failure, don't reconnect.
author Timo Sirainen <tss@iki.fi>
date Mon, 10 Sep 2007 09:24:10 +0300
parents b5dd8d64b4ae
children f7cc3723ad99
files src/auth/db-ldap.c
diffstat 1 files changed, 60 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/src/auth/db-ldap.c	Sun Sep 09 06:42:10 2007 +0300
+++ b/src/auth/db-ldap.c	Mon Sep 10 09:24:10 2007 +0300
@@ -150,7 +150,7 @@
 	if (ret != LDAP_SUCCESS) {
 		i_error("LDAP: Can't get error number: %s",
 			ldap_err2string(ret));
-		return -1;
+		return LDAP_UNAVAILABLE;
 	}
 
 	return err;
@@ -193,17 +193,66 @@
 	conn->retrying = FALSE;
 }
 
+static void ldap_conn_reconnect(struct ldap_connection *conn)
+{
+	ldap_conn_close(conn, FALSE);
+
+	if (db_ldap_connect(conn) < 0) {
+		/* failed to reconnect. fail all requests. */
+		ldap_conn_close(conn, TRUE);
+	}
+}
+
+static void ldap_handle_error(struct ldap_connection *conn)
+{
+	int err = ldap_get_errno(conn);
+
+	switch (err) {
+	case LDAP_SUCCESS:
+		i_unreached();
+	case LDAP_SIZELIMIT_EXCEEDED:
+	case LDAP_TIMELIMIT_EXCEEDED:
+	case LDAP_NO_SUCH_ATTRIBUTE:
+	case LDAP_UNDEFINED_TYPE:
+	case LDAP_INAPPROPRIATE_MATCHING:
+	case LDAP_CONSTRAINT_VIOLATION:
+	case LDAP_TYPE_OR_VALUE_EXISTS:
+	case LDAP_INVALID_SYNTAX:
+	case LDAP_NO_SUCH_OBJECT:
+	case LDAP_ALIAS_PROBLEM:
+	case LDAP_INVALID_DN_SYNTAX:
+	case LDAP_IS_LEAF:
+	case LDAP_ALIAS_DEREF_PROBLEM:
+	case LDAP_FILTER_ERROR:
+		/* invalid input */
+		break;
+	case LDAP_SERVER_DOWN:
+	case LDAP_TIMEOUT:
+	case LDAP_UNAVAILABLE:
+	case LDAP_BUSY:
+#ifdef LDAP_CONNECT_ERROR
+	case LDAP_CONNECT_ERROR:
+#endif
+	case LDAP_LOCAL_ERROR:
+	case LDAP_INVALID_CREDENTIALS:
+	default:
+		/* connection problems */
+		ldap_conn_reconnect(conn);
+		break;
+	}
+}
+
 void db_ldap_search(struct ldap_connection *conn, struct ldap_request *request,
 		    int scope)
 {
-	int msgid;
+	int try, msgid = -1;
 
 	if (db_ldap_connect(conn) < 0) {
 		request->callback(conn, request, NULL);
 		return;
 	}
 
-	if (conn->connected && !conn->binding) {
+	for (try = 0; conn->connected && !conn->binding && try < 2; try++) {
 		if (conn->last_auth_bind) {
 			/* switch back to the default dn before doing the
 			   search request. */
@@ -211,8 +260,7 @@
 				request->callback(conn, request, NULL);
 				return;
 			}
-			db_ldap_add_delayed_request(conn, request);
-			return;
+			break;
 		}
 
 		msgid = ldap_search(conn->ld, request->base, scope,
@@ -220,13 +268,14 @@
 		if (msgid == -1) {
 			i_error("LDAP: ldap_search() failed (filter %s): %s",
 				request->filter, ldap_get_error(conn));
-			request->callback(conn, request, NULL);
-			return;
+			ldap_handle_error(conn);
 		}
+	}
+
+	if (msgid != -1)
 		hash_insert(conn->requests, POINTER_CAST(msgid), request);
-	} else {
+	else
 		db_ldap_add_delayed_request(conn, request);
-	}
 }
 
 static void ldap_conn_retry_requests(struct ldap_connection *conn)
@@ -307,16 +356,6 @@
 	conn->retrying = FALSE;
 }
 
-static void ldap_conn_reconnect(struct ldap_connection *conn)
-{
-	ldap_conn_close(conn, FALSE);
-
-	if (db_ldap_connect(conn) < 0) {
-		/* failed to reconnect. fail all requests. */
-		ldap_conn_close(conn, TRUE);
-	}
-}
-
 static void ldap_input(struct ldap_connection *conn)
 {
         struct ldap_request *request;
@@ -354,9 +393,8 @@
 	}
 
 	if (ret < 0) {
-		i_error("LDAP: ldap_result() failed: %s",
-			ldap_get_error(conn));
-		ldap_conn_reconnect(conn);
+		i_error("LDAP: ldap_result() failed: %s", ldap_get_error(conn));
+		ldap_handle_error(conn);
 	} else {
 		if (!conn->binding)
 			db_ldap_handle_next_delayed_request(conn);