From 5d41807f4d6b80dd1c51ce2764521a2a38c88936 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 5 Dec 2001 09:19:25 +0000 Subject: [PATCH] added timeouts and retries to ldap operations (This used to be commit 4f004eb54d66b6f811cb2f4791da6c70d77f87c2) --- source3/include/ads.h | 7 +++++ source3/libads/ldap.c | 62 ++++++++++++++++++++++++++++++++++++------- 2 files changed, 60 insertions(+), 9 deletions(-) diff --git a/source3/include/ads.h b/source3/include/ads.h index 49dcdd9a434..36351c1c2bf 100644 --- a/source3/include/ads.h +++ b/source3/include/ads.h @@ -11,9 +11,16 @@ typedef struct { char *kdc_server; int ldap_port; char *bind_path; + time_t last_attempt; } ADS_STRUCT; +/* time between reconnect attempts */ +#define ADS_RECONNECT_TIME 5 + +/* timeout on searches */ +#define ADS_SEARCH_TIMEOUT 10 + #define UF_DONT_EXPIRE_PASSWD 0x10000 #define UF_MNS_LOGON_ACCOUNT 0x20000 #define UF_SMARTCARD_REQUIRED 0x40000 diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c index b18e7927ae8..14fd716058b 100644 --- a/source3/libads/ldap.c +++ b/source3/libads/ldap.c @@ -62,6 +62,8 @@ int ads_connect(ADS_STRUCT *ads) int version = LDAP_VERSION3; int rc; + ads->last_attempt = time(NULL); + ads->ld = ldap_open(ads->ldap_server, ads->ldap_port); if (!ads->ld) { return errno; @@ -75,6 +77,50 @@ int ads_connect(ADS_STRUCT *ads) return rc; } +/* + a wrapper around ldap_search_s that retries depending on the error code + this is supposed to catch dropped connections and auto-reconnect +*/ +int ads_search_retry(ADS_STRUCT *ads, const char *bind_path, int scope, const char *exp, + const char **attrs, void **res) +{ + struct timeval timeout; + int rc = -1, rc2; + int count = 3; + + if (!ads->ld && + time(NULL) - ads->last_attempt < ADS_RECONNECT_TIME) { + return LDAP_SERVER_DOWN; + } + + while (count--) { + *res = NULL; + timeout.tv_sec = ADS_SEARCH_TIMEOUT; + timeout.tv_usec = 0; + if (ads->ld) { + rc = ldap_search_ext_s(ads->ld, bind_path, scope, exp, attrs, 0, NULL, NULL, + &timeout, LDAP_NO_LIMIT, (LDAPMessage **)res); + if (rc == 0) return rc; + } + + if (*res) ads_msgfree(ads, *res); + *res = NULL; + DEBUG(1,("Reopening ads connection after error %s\n", ads_errstr(rc))); + if (ads->ld) { + /* we should unbind here, but that seems to trigger openldap bugs :( + ldap_unbind(ads->ld); + */ + } + ads->ld = NULL; + rc2 = ads_connect(ads); + if (rc2) { + DEBUG(1,("ads_search_retry: failed to reconnect (%s)\n", ads_errstr(rc))); + return rc2; + } + } + DEBUG(1,("ads reopen failed after error %s\n", ads_errstr(rc))); + return rc; +} /* do a general ADS search @@ -83,9 +129,7 @@ int ads_search(ADS_STRUCT *ads, void **res, const char *exp, const char **attrs) { - *res = NULL; - return ldap_search_s(ads->ld, ads->bind_path, - LDAP_SCOPE_SUBTREE, exp, (char **)attrs, 0, (LDAPMessage **)res); + return ads_search_retry(ads, ads->bind_path, LDAP_SCOPE_SUBTREE, exp, attrs, res); } /* @@ -95,9 +139,7 @@ int ads_search_dn(ADS_STRUCT *ads, void **res, const char *dn, const char **attrs) { - *res = NULL; - return ldap_search_s(ads->ld, dn, - LDAP_SCOPE_BASE, "(objectclass=*)", (char **)attrs, 0, (LDAPMessage **)res); + return ads_search_retry(ads, dn, LDAP_SCOPE_BASE, "(objectclass=*)", attrs, res); } /* @@ -535,11 +577,13 @@ BOOL ads_USN(ADS_STRUCT *ads, uint32 *usn) const char *attrs[] = {"highestCommittedUSN", NULL}; int rc; void *res; + BOOL ret; - rc = ldap_search_s(ads->ld, "", - LDAP_SCOPE_BASE, "(objectclass=*)", attrs, 0, (LDAPMessage **)&res); + rc = ads_search_retry(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res); if (rc || ads_count_replies(ads, res) != 1) return False; - return ads_pull_uint32(ads, res, "highestCommittedUSN", usn); + ret = ads_pull_uint32(ads, res, "highestCommittedUSN", usn); + ads_msgfree(ads, res); + return ret; }