]> git.sur5r.net Git - openldap/commitdiff
ITS#6625,ITS#5421
authorQuanah Gibson-Mount <quanah@openldap.org>
Thu, 6 Jan 2011 19:43:18 +0000 (19:43 +0000)
committerQuanah Gibson-Mount <quanah@openldap.org>
Thu, 6 Jan 2011 19:43:18 +0000 (19:43 +0000)
35 files changed:
CHANGES
clients/tools/ldapmodify.c
clients/tools/ldapsearch.c
doc/drafts/draft-zeilenga-ldap-c-api-concurrency-xx.txt [new file with mode: 0644]
doc/man/man3/ldap_dup.3 [new file with mode: 0644]
doc/man/man3/ldap_dup.3.links [new file with mode: 0644]
doc/man/man3/ldap_get_option.3
include/ldap.h
include/ldap_int_thread.h
include/ldap_pvt_thread.h
libraries/libldap/abandon.c
libraries/libldap/cyrus.c
libraries/libldap/gssapi.c
libraries/libldap/init.c
libraries/libldap/ldap-int.h
libraries/libldap/open.c
libraries/libldap/options.c
libraries/libldap/request.c
libraries/libldap/result.c
libraries/libldap/tls2.c
libraries/libldap/tls_g.c
libraries/libldap/tls_m.c
libraries/libldap/tls_o.c
libraries/libldap/unbind.c
libraries/liblutil/fetch.c
libraries/liblutil/ntservice.c
servers/slapd/back-ldap/search.c
servers/slapd/back-meta/map.c
servers/slapd/back-meta/search.c
servers/slapd/overlays/rwmmap.c
tests/progs/Makefile.in
tests/progs/slapd-mtread.c [new file with mode: 0644]
tests/scripts/defines.sh
tests/scripts/test060-mt-hot [new file with mode: 0755]
tests/scripts/test061-syncreplication-initiation [new file with mode: 0755]

diff --git a/CHANGES b/CHANGES
index 5a44a4541416c856cd5f8214568537b07214b96a..1e09175e619e60b9cdd22fed686356f98c9e489a 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -2,6 +2,7 @@ OpenLDAP 2.4 Change Log
 
 OpenLDAP 2.4.24 Engineering
        Added LDIF line wrapping setting (ITS#6645)
+       Added libldap concurrency support (ITS#6625,ITS#5421)
        Added libldap MozNSS non-blocking support (ITS#6714)
        Added libldap MozNSS cert centralization (ITS#6742)
        Added libldap x500UniqueIdentifier handling (ITS#6741)
index 210e8764ada923aaf2189a8bef9f04428b239aae..7cd9774de59ebb7a13528fb3a781f4060b681aa9 100644 (file)
@@ -64,7 +64,6 @@
 #include "lutil_ldap.h"
 #include "ldif.h"
 #include "ldap_defaults.h"
-#include "ldap_log.h"
 #include "ldap_pvt.h"
 #include "lber_pvt.h"
 
index 0c672c18b8223707ea73e5e771e266ff5e4a427e..4e4f893b8f2632cc210ef4858a213d517fb68f03 100644 (file)
@@ -66,7 +66,6 @@
 #include "lutil.h"
 #include "lutil_ldap.h"
 #include "ldap_defaults.h"
-#include "ldap_log.h"
 #include "ldap_pvt.h"
 
 #include "common.h"
diff --git a/doc/drafts/draft-zeilenga-ldap-c-api-concurrency-xx.txt b/doc/drafts/draft-zeilenga-ldap-c-api-concurrency-xx.txt
new file mode 100644 (file)
index 0000000..271556a
--- /dev/null
@@ -0,0 +1,714 @@
+INTERNET-DRAFT                                        Kurt D. Zeilenga
+Intended Category: Standards Track                 OpenLDAP Foundation
+Extends: draft-ietf-ldapext-ldap-c-api-03.txt
+Expires: 28 March 2000
+                                                     28 September 1999
+
+                    LDAP C API Concurrency Extensions
+              <draft-zeilenga-ldap-c-api-concurrency-00.txt>
+
+1.   Status of this Memo
+
+  This document is an Internet-Draft and is in full conformance with all
+  provisions of Section 10 of RFC2026.
+
+  This draft document will be submitted to the RFC Editor as a Standards
+  Track document. Distribution of this memo is unlimited.  Technical
+  discussion of this document will take place on the IETF LDAP Extension
+  Working Group mailing list <ietf-ldapext@netscape.com>.  Please send
+  editorial comments directly to the author <Kurt@OpenLDAP.org>.
+
+  Internet-Drafts are working documents of the Internet Engineering Task
+  Force (IETF), its areas, and its working groups.  Note that other
+  groups may also distribute working documents as Internet-Drafts.
+
+  Internet-Drafts are draft documents valid for a maximum of six months
+  and may be updated, replaced, or obsoleted by other documents at any
+  time.  It is inappropriate to use Internet-Drafts as reference
+  material or to cite them other than as "work in progress."
+
+  The list of current Internet-Drafts can be accessed at
+  http://www.ietf.org/ietf/1id-abstracts.txt
+
+  The list of Internet-Draft Shadow Directories can be accessed at
+  http://www.ietf.org/shadow.html.
+
+  Copyright 1999, The Internet Society.  All Rights Reserved.
+
+  Please see the Copyright section near the end of this document for
+  more information.
+
+2.   Abstract
+
+  This document defines extensions to the LDAP C API to support use in
+  concurrent execution environments.  The document describes and defines
+
+Zeilenga                                                        [Page 1]
+
+INTERNET-DRAFT      LDAP C API Concurrency Extensions  28 September 1999
+
+  requirements for multiple concurrency levels: thread safe, session
+  thread safe, and operation thread safe.
+
+  The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+  "SHOULD", "SHOULD NOT", "RECOMMENDED",  and "MAY" in this document are
+  to be interpreted as described in RFC 2119 [KEYW].
+
+3.   Introduction
+
+  This document extends the LDAP C API [CAPI] specification to support
+  use in concurrent execution environments.  The extensions add powerful
+  concurrent processing capabilities to the simple to use CAPI.  This
+  document provides an overview of different levels of concurrent
+  execution support and offers a number of CAPI "features" to provide
+  capabilities at these levels.
+
+  The remainder of this section describes three levels of concurrent
+  execution: thread safe, session thread safe, operation thread safe
+  APIs.
+
+3.1. Thread Safe
+
+  An implementation which allows applications to safely execute in
+  concurrent execution environments where the application provides
+  necessary synchronization to ensure serialization of CAPI usage is
+  considered to be "thread safe."   Applications may execute non-CAPI
+  calls in concurrent execution contexts when using thread safe
+  implementations.
+
+3.2. Session Thread Safe
+
+  A "thread safe" implementation which allows CAPI calls associated with
+  different LDAP sessions to proceed asychronously is considered to be
+  "session thread safe."
+
+3.3. Operation Thread Safe
+
+  A "session thread safe" implementation which allows CAPI calls
+  associated with different LDAP operations to proceed asychronously is
+  considered to be "operation thread safe".
+
+4.   Basic Thread Safe Feature
+
+Zeilenga                                                        [Page 2]
+
+INTERNET-DRAFT      LDAP C API Concurrency Extensions  28 September 1999
+
+  This section details requirements for the thread safe CAPI feature.
+  Implementations fulfilling these requirements are said to support the
+  LDAP_API_FEATURE_THREAD_SAFE feature and SHOULD advertise this support
+  as detailed below.  This feature SHOULD be provided by
+  implementations.
+
+  Implementations of this feature MUST implement the LDAP error handling
+  extension [ERRNO].
+
+  Implementations of this feature MUST allow non-CAPI calls to proceed
+  asynchronously.
+
+  Implementations of this feature MUST NOT use any non-thread safe call
+  or mechanism provided by C environment or operating system.  An
+  example of non-reentrant calls is the UNIX strtok() function.  Example
+  of a non-reentrant mechanism is global (i.e.: non-thread specific)
+  errno.
+
+5.   Session Thread Safe Feature
+
+  This section details requirements for the session thread safe CAPI
+  feature.  Implementations fulfilling these requirements are said to
+  support the LDAP_API_FEATURE_SESSION_THREAD_SAFE feature and SHOULD
+  advertise this support as detailed below.  This feature is
+  RECOMMENDED.
+
+5.1. Prerequisite Features
+
+  Implementations providing this feature MUST provide and advertise both
+  LDAP_API_FEATURE_CONTEXT_SPECIFIC_ERRNO [ERRNO] and
+  LDAP_API_FEATURE_THREAD_SAFE.
+
+5.2. Atomic Session Handles
+
+  Implementations providing this feature SHOULD ensure that operations
+  upon a given session handle are atomic.  Implementations which provide
+  atomic session handles SHOULD advertise the feature
+  LDAP_API_FEATURE_ATOMIC_SESSION_HANDLES.
+
+5.3. Concurrency Requirements
+
+  Implementations providing this feature MUST not restrict CAPI calls
+  acting upon a given LDAP session to a particular execution context.
+  Applications MAY use a session handle on any thread.  Applications
+
+Zeilenga                                                        [Page 3]
+
+INTERNET-DRAFT      LDAP C API Concurrency Extensions  28 September 1999
+
+  MUST NOT assume that operations upon a session are atomic.
+
+  Implementations providing this feature MUST allow CAPI calls acting
+  upon different LDAP sessions to safely proceed asynchronously.
+
+  Implementations providing this feature MUST allow CAPI calls not
+  acting upon an LDAP session to safely proceed asynchronously.
+
+6.   Operation Thread Safe Feature
+
+  This section details requirements for the operation thread safe CAPI
+  feature based upon a duplicate session handles mechanism.
+
+  Implementations fulfilling these requirements are said to support the
+  LDAP_API_FEATURE_DUPLICATE_SESSION_HANDLES feature and SHOULD
+  advertise this support as detailed below.  This feature is OPTIONAL.
+
+6.1. Prerequisite Features
+
+  Implementations of this feature MUST provide and advertise
+  LDAP_API_FEATURE_CONTEXT_SPECIFIC_ERRNO [ERRNO],
+  LDAP_API_FEATURE_THREAD_SAFE, LDAP_API_FEATURE_SESSION_THREAD_SAFE,
+  and LDAP_API_FEATURE_ATOMIC_SESSION_HANDLES.
+
+6.2. Duplicated Session Handles
+
+  Implementations of this feature MUST support duplicated session
+  handles.
+
+  As defined in CAPI, a session handle refers to an LDAP session
+  encompassing connections with one or more servers, associated message
+  results, a set of properties (options), and state information.  This
+  feature provides a mechanism for a handle to be duplicated.  A session
+  handle and its duplicates are considered siblings.  Each sibling
+  session handle refers to the same LDAP session and message results.
+  Some properties and state are specific to a handle and others shared
+  between siblings as detailed below.
+
+  CAPI calls made on a handle are atomic.  Calls made on sibling (or
+  other) handles MAY proceed asynchronously.
+
+  Session handles are duplicated using ldap_dup() and destroyed using
+  ldap_destroy().  Use of duplicated session handles with CAPI calls
+  have the following semantics detailed in the sections below.
+
+Zeilenga                                                        [Page 4]
+
+INTERNET-DRAFT      LDAP C API Concurrency Extensions  28 September 1999
+
+6.2.1.    Creating and Destroying duplicated sessions
+
+  Implementations of this feature are required to provide two new
+  routines:      LDAP *ldap_dup( ld );      int ldap_destroy( ld );
+
+  Parameters are:      ld      The session handle
+
+  The ldap_dup() function returns a duplicate of a session handle.  The
+  returned session handle may be used concurrently with the original
+  session handle as described below. ldap_dup returns NULL if it is not
+  able to duplicate the session handle and sets LDAP_OPT_ERROR_NUMBER
+  and ldap_errno indicating the nature of the failure.
+
+  The ldap_destroy() function destroys the session handle.  If the
+  session handle has no siblings, ldap_destroy behaves exactly like
+  ldap_unbind.  If the session handle has siblings, the resources
+  assocated with the handle are released and the siblings remain valid.
+  ldap_destroy() returns LDAP_SUCCESS or an error number indicating the
+  nature of failure.  Regardless of returned value, the handle SHOULD be
+  considered invalid and MUST not be used in subsequent calls.  Attempts
+  to use a destroyed session handle MUST NOT result in
+  LDAP_INVALID_SESSION error being reported.  Implementations SHOULD
+  report LDAP_PARAM_ERROR in such cases.
+
+6.2.2.    ldap_unbind and siblings
+
+  When ldap_unbind() is called on a session handle with siblings, the
+  siblings become invalid.  The siblings must be destroyed using
+  ldap_destroy().  All attempts to obtain the siblings'
+  LDAP_OPT_ERROR_NUMBER will return LDAP_INVALID_SESSION.  Any use other
+  than ldap_destroy() or reading LDAP_OPT_ERROR_NUMBER will fail with an
+  LDAP_INVALID_SESSION error being reported.
+
+6.2.3.    ldap_result()
+
+  Message queues are shared between siblings.  Results of operations on
+  a duplicated session handles are accessible to all sibling session
+  handles.
+
+  Applications desiring results associated with a specific operation
+  SHOULD provide the appropriate msgid to ldap_result().  Applications
+  SHOULD avoid calling ldap_result() with LDAP_RES_ANY as such may
+  "steal" and return results which an operation on a sibling requires to
+  complete.
+
+Zeilenga                                                        [Page 5]
+
+INTERNET-DRAFT      LDAP C API Concurrency Extensions  28 September 1999
+
+6.2.4.    Session Options
+
+  The following CAPI options access values shared between siblings:
+
+       LDAP_OPT_API_INFO      LDAP_OPT_DESC      LDAP_OPT_REFERRALS
+       LDAP_OPT_PROTOCOL_VERSION      LDAP_OPT_API_FEATURE_INFO
+       LDAP_OPT_HOST_NAME
+
+  The following CAPI options access values specific to a sibling:
+
+       LDAP_OPT_DEREF      LDAP_OPT_SIZELIMIT      LDAP_OPT_TIMELIMIT
+       LDAP_OPT_RESTART      LDAP_OPT_CLIENT_CONTROLS
+       LDAP_OPT_SERVER_CONTROLS      LDAP_OPT_ERROR_NUMBER
+       LDAP_OPT_ERROR_STRING      LDAP_OPT_MATCHED_DN
+
+6.2.4.1.  LDAP_OPT_SESSION_REFCNT
+
+  In addition, implementations MUST provide the READ-ONLY, shared
+  LDAP_OPT_SESSION_REFCNT option.  LDAP_OPT_SESSION_REFCNT returns the
+  reference count associated with the supplied session handle argument.
+  The session handle argument is required. The outvalue argument should
+  be a pointer to an integer.  Example use:
+
+      int refcount(LDAP *ld) {
+
+      #ifdef LDAP_OPT_SESSION_REFCNT
+
+        if(ld != NULL) {
+          int refcnt, rc;
+          rc = ldap_get_option(ld,
+              LDAP_OPT_SESSION_REFCNT, &refcnt);
+
+          if(rc == LDAP_OPT_SUCCESS) {
+            return refcnt;
+          }
+        }
+
+      #endif
+
+        return -1;
+      }
+
+7.   Advertising Features
+
+  This document REQUIRES that supported features with the name in the
+  form LDAP_API_FEATURE_x be advertised to consumers of the CAPI as
+
+Zeilenga                                                        [Page 6]
+
+INTERNET-DRAFT      LDAP C API Concurrency Extensions  28 September 1999
+
+  follows:
+
+       SHOULD provide the macro LDAP_API_FEATURE_x with the value
+       of 1000 + revision number of this draft (i.e.: 1000+0 for
+       this 0 revision of the draft).
+
+       MUST provide the CAPI extension "x" when returning API
+       information upon LDAP_OPT_API_INFO option access, and
+
+       MUST provide feature info for "x" via LDAP_OPT_FEATURE_INFO
+       option mechanism.  The feature version provided MUST      match
+  the value LDAP_API_FEATURE_x macro
+
+  where x is replaced appropriately.
+
+  As implementations may not provide macros for all features,
+  applications SHOULD use LDAP_OPT_API_INFO to determine which features
+  are provided by a given implementation.
+
+8.   Changes to the C API specification
+
+8.1. New Symbols
+
+  This extension introduces the following macros:
+
+       LDAP_API_FEATURE_ATOMIC_SESSION_HANDLES
+       LDAP_API_FEATURE_DUPLICATE_SESSION_HANDLES
+       LDAP_API_FEATURE_SESSION_THREAD_SAFE
+       LDAP_API_FEATURE_THREAD_SAFE
+       LDAP_API_FEATURE_OPERATION_THREAD_SAFE      LDAP_INVALID_SESSION
+       LDAP_OPT_SESSION_REFCNT
+
+  This extension introduces these new functions:
+
+       ldap_destroy()      ldap_dup()
+
+  This extension introduces no new typedefs nor structure names.
+
+8.2. Duplicated Session Handles
+
+  This extension introduces duplicated session handles and requirements
+  for handling duplicated session handles.  Semantics of non-duplicated
+  session handles are not affected by this introduction.  However, the
+  semantics of calls upon duplicate session handles differs as described
+  in the extension.
+
+Zeilenga                                                        [Page 7]
+
+INTERNET-DRAFT      LDAP C API Concurrency Extensions  28 September 1999
+
+9.   Security Considerations
+
+  None taken, none given.
+
+10.  Copyright
+
+  Copyright 1999, The Internet Society.  All Rights Reserved.
+
+  This document and translations of it may be copied and furnished to
+  others, and derivative works that comment on or otherwise explain it
+  or assist in its implementation may be prepared, copied, published and
+  distributed, in whole or in part, without restriction of any kind,
+  provided that the above copyright notice and this paragraph are
+  included on all such copies and derivative works.  However, this
+  document itself may not be modified in any way, such as by removing
+  the copyright notice or references to the Internet Society or other
+  Internet organizations, except as needed for the  purpose of
+  developing Internet standards in which case the procedures for
+  copyrights defined in the Internet Standards process must be followed,
+  or as required to translate it into languages other than English.
+
+  The limited permissions granted above are perpetual and will not be
+  revoked by the Internet Society or its successors or assigns.
+
+  This document and the information contained herein is provided on an
+  "AS IS" basis and THE AUTHORS, THE INTERNET SOCIETY, AND THE INTERNET
+  ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
+  INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
+  INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+  WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+11.  Bibliography
+
+  [CAPI]  M. Smith, T. Howes, A. Herron, M. Wahl, A. Anantha,      "The
+  C LDAP Application Program Interface", INTERNET-DRAFT,      <draft-
+  ietf-ldapext-ldap-c-api-03.txt> + LDAPext discussions,      June 1999.
+
+  [ERRNO] K. Zeilenga, "LDAP C API Error Reporting Extension",
+       INTERNET-DRAFT, <draft-zeilenga-ldap-c-api-errno-00.txt>,
+       June 1999.
+
+  [KEYW]  S. Bradner, "Key words for use in RFCs to Indicate
+       Requirement Levels", RFC 2119, March 1997.
+
+Zeilenga                                                        [Page 8]
+
+INTERNET-DRAFT      LDAP C API Concurrency Extensions  28 September 1999
+
+  [LDAP]  M. Wahl, T. Howes, S. Kille, "Lightweight Directory
+       Access Protocol (v3)", RFC 2251, December 1997.
+
+13.  Author's Address
+
+  Kurt D. Zeilenga
+  OpenLDAP Foundation
+  <Kurt@OpenLDAP.org>
+
+  This document expires on 28 March 2000.
+
+Zeilenga                                                        [Page 9]
+
+    ---------------------------------------------------------------------
+
+INTERNET-DRAFT                                        Kurt D. Zeilenga
+Intended Category: Standards Track                 OpenLDAP Foundation
+Extends: draft-ietf-ldapext-ldap-c-api-03.txt
+Expires: 28 March 2000
+                                                     28 September 1999
+
+                   LDAP C API Error Reporting Extension
+                 <draft-zeilenga-ldap-c-api-errno-00.txt>
+
+1.   Status of this Memo
+
+  This document is an Internet-Draft and is in full conformance with all
+  provisions of Section 10 of RFC2026.
+
+  This draft document will be submitted to the RFC Editor as a Standards
+  Track document. Distribution of this memo is unlimited.  Technical
+  discussion of this document will take place on the IETF LDAP Extension
+  Working Group mailing list <ietf-ldapext@netscape.com>.  Please send
+  editorial comments directly to the author <Kurt@OpenLDAP.org>.
+
+  Internet-Drafts are working documents of the Internet Engineering Task
+  Force (IETF), its areas, and its working groups.  Note that other
+  groups may also distribute working documents as Internet-Drafts.
+
+  Internet-Drafts are draft documents valid for a maximum of six months
+  and may be updated, replaced, or obsoleted by other documents at any
+  time.  It is inappropriate to use Internet-Drafts as reference
+  material or to cite them other than as ``work in progress.''
+
+  The list of current Internet-Drafts can be accessed at
+  http://www.ietf.org/ietf/1id-abstracts.txt
+
+  The list of Internet-Draft Shadow Directories can be accessed at
+  http://www.ietf.org/shadow.html.
+
+  Copyright 1999, The Internet Society.  All Rights Reserved.
+
+  Please see the Copyright section near the end of this document for
+  more information.
+
+2.   Abstract
+
+  This document defines a manatory extension to the LDAP C API to
+  provide error reporting for all API calls.  The mechanism is
+  nonintrusive and can, optionally, support concurrent execution
+  environments.
+
+Zeilenga                                                        [Page 1]
+
+INTERNET-DRAFT    LDAP C API Error Reporting Extension 28 September 1999
+
+  The key words ``MUST'', ``MUST NOT'', ``REQUIRED'', ``SHALL'', ``SHALL
+  NOT'', ``SHOULD'', ``SHOULD NOT'', ``RECOMMENDED'',  and ``MAY'' in
+  this document are to be interpreted as described in RFC 2119 [KEYW].
+
+3.   Background and Intent of Use
+
+  The LDAP [LDAP] C API [CAPI] provides an interface which (due to
+  legacy compatibiity issues) does not provide a consistent mechanism
+  for reporting errors.  A large number of the calls within the
+  specification have no mechanism to indicate the nature of a failure.
+  The usefulness of a CAPI without a consistent, easy to use, error
+  reporting mechanism is limited.
+
+  This document defines an mandatory extension to the CAPI.  All
+  implementations of the CAPI MUST provide this extension.
+
+  The extension details additional requirements for error reporting.
+  Implementations MUST fulfill all other CAPI error reporting
+  requirements.
+
+4.   Error Handling Extension
+
+  This extension provides a mechanism that applications MAY use to
+  obtain an LDAP error number indicating the nature of the failure
+  associated with the last failed CAPI call.
+
+  Implementations MUST provide access to an LDAP error number (CAPI,
+  Section 9) resulting from the last failed CAPI call via the symbol
+  ldap_errno.  The last failed CAPI call may be within the global
+  context or within the current execution context.
+
+  The ldap_errno MUST evaluate to a modifiable lvalue that has type
+  'int', the value of which is set to a LDAP error number.  It is
+  unspecified whether ldap_errno is a macro or an identifier declared
+  with external linkage.  If a macro definition is suppressed in order
+  to access an actual object, or a program defines an identifier with
+  the name ldap_errno, the behavior is undefined.
+
+  Applications MUST access ldap_errno within the same concurrent
+  execution context, commonly a thread, in which the failure occurred.
+  The value of ldap_errno is LDAP_SUCCESS (0) if no API failure has
+  occurred within the supported context and the user has not assigned a
+  value within the supported context.
+
+Zeilenga                                                        [Page 2]
+
+INTERNET-DRAFT    LDAP C API Error Reporting Extension 28 September 1999
+
+  Implementations SHALL NOT update the ldap_errno value upon successful
+  CAPI call completion.
+
+  Implementations providing a current execution context specific
+  ldap_errno MUST advertise the feature LDAP_API_CONTEXT_SPECIFIC_ERRNO
+  as described in Section 6.  Implementation of
+  LDAP_API_CONTEXT_SPECIFIC_ERRNO is RECOMMENDED.
+
+4.1. Reporting Server Errors
+
+  It is not a CAPI failure for a server to return an error number.
+  Implementations SHALL NOT assign error results returned by servers to
+  ldap_errno.
+
+4.2. Implementation Specific Reporting
+
+  The CAPI specification stated that the caller may obtain an indication
+  of failure of certain calls (see listed below) using implementation
+  specific and/or operating system specific requirements.
+  Implementations are NOT REQUIRED to support any implementation
+  specific and/or operating system mechanism for ANY call detailed by
+  the CAPI specification or its extensions.
+
+  Affected calls include ldap_init(), ldap_open(), and ber_*().
+
+4.3. Example
+
+  The following is an example showing how an application may obtain the
+  error information resulting from a failed CAPI calls:
+
+    int msgid;
+    LDAP *ld = ldap_init("localhost", 389);
+
+    if(ld == NULL) {
+      printf("ldap_init failed, ldap_errno=%d (%s)\n",
+        ldap_errno, ldap_err2string(ldap_errno));
+
+      printf("unable to initialize LDAP session\n");
+      return -1;
+    }
+
+    msgid = ldap_simple_bind(ld, NULL, NULL);
+
+    if(msgid == -1) {
+      int err = ldap_errno;
+
+      if (err != LDAP_SUCCESS ) {
+
+Zeilenga                                                        [Page 3]
+
+INTERNET-DRAFT    LDAP C API Error Reporting Extension 28 September 1999
+
+        /* API failure */
+        printf("ldap_simple_bind failure: ldap_errno=%d (%s)\n",
+          err, ldap_err2string(err));
+
+      } else {
+        int lderr, rc;
+
+        printf("ldap_simple_bind failed\n");
+
+        rc = ldap_get_option(ld,
+          LDAP_OPT_ERROR_NUMBER, &lderr);
+
+        if(rc == LDAP_OPT_SUCCESS) {
+          printf("  reason=%d (%s)\n",
+            lderr, ldap_err2string(lderr));
+
+        } else {
+          printf("ldap_get_option failed, ldap_errno=%d (%s)\n",
+            ldap_errno, ldap_err2string(ldap_errno));        }
+      }
+
+      goto unbind;
+    }
+
+    /* ... */
+
+    unbind: if(ldap_unbind(ld) != 0) {
+      printf("ldap_unbind failed, ldap_errno=%d (%s)\n",
+        ldap_errno, ldap_error2str(ldap_errno));
+
+      return -1;
+    }
+    return 0;
+
+5.   Advertising Features
+
+  This document REQUIRES that supported features with the name in the
+  form LDAP_API_FEATURE_x be advertised to consumers of the CAPI as
+  follows:
+
+       SHOULD provide the macro LDAP_API_FEATURE_x with the value
+       of 1000 + revision number of this draft (i.e.: 1000+0 for
+       this 0 revision of the draft).
+
+       MUST provide the CAPI extension "x" when returning API
+       information upon LDAP_OPT_API_INFO option access, and
+
+Zeilenga                                                        [Page 4]
+
+INTERNET-DRAFT    LDAP C API Error Reporting Extension 28 September 1999
+
+       MUST provide feature info for "x" via LDAP_OPT_FEATURE_INFO
+       option mechanism.  The feature version provided MUST      match
+  the value LDAP_API_FEATURE_x macro
+
+  where x is replaced appropriately.
+
+  As implementations may not provide macros for all features,
+  applications SHOULD use LDAP_OPT_API_INFO to determine which features
+  are provided by a given implementation.
+
+6.   Changes to the LDAP C API
+
+  This section provides a summary of changes to the CAPI specification.
+
+6.1. LDAP_API_VERSION
+
+  LDAP_API_VERSION should be set to the RFC number of this extension if
+  and when it is published as a Standards Track RFC.  (see purpose of
+  this draft above).
+
+  Until such time as this document is published as an RFC,
+  implementations should use the value specified by CAPI plus 100 + 10 *
+  the number of this draft.
+
+  For the third draft of CAPI and this 0 revision of draft, the value of
+  2103 ((2000+3) + (100+10*0)) should be used.
+
+6.2. New Symbols
+
+  This extension introduces two new symbols:
+       LDAP_API_FEATURE_CONTEXT_SPECIFIC_ERRNO      ldap_errno
+
+  LDAP_API_FEATURE_CONTEXT_SPECIFIC_ERRNO is a macro.  ldap_errno MAY be
+  a MACRO.
+
+  This extension indroductes no new functions, typedefs, or structure
+  names.
+
+6.3. Implementation/System Specific Error Handling
+
+  This extensions removes any requirements that implementations to use
+  implementation and/or operating system specific error reporting
+  mechanisms.
+
+Zeilenga                                                        [Page 5]
+
+INTERNET-DRAFT    LDAP C API Error Reporting Extension 28 September 1999
+
+7.   Security Considerations
+
+  None taken, none given.
+
+8.   Copyright
+
+  Copyright 1999, The Internet Society.  All Rights Reserved.
+
+  This document and translations of it may be copied and furnished to
+  others, and derivative works that comment on or otherwise explain it
+  or assist in its implementation may be prepared, copied, published and
+  distributed, in whole or in part, without restriction of any kind,
+  provided that the above copyright notice and this paragraph are
+  included on all such copies and derivative works.  However, this
+  document itself may not be modified in any way, such as by removing
+  the copyright notice or references to the Internet Society or other
+  Internet organizations, except as needed for the  purpose of
+  developing Internet standards in which case the procedures for
+  copyrights defined in the Internet Standards process must be followed,
+  or as required to translate it into languages other than English.
+
+  The limited permissions granted above are perpetual and will not be
+  revoked by the Internet Society or its successors or assigns.
+
+  This document and the information contained herein is provided on an
+  "AS IS" basis and THE AUTHORS, THE INTERNET SOCIETY, AND THE INTERNET
+  ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
+  INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
+  INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+  WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+9.   Bibliography
+
+  [CAPI]  M. Smith, T. Howes, A. Herron, M. Wahl, A. Anantha,
+          "The C LDAP Application Program Interface", INTERNET-DRAFT,
+          <draft-ietf-ldapext-ldap-c-api-03.txt> + LDAPext discussions,
+       June 1999.
+
+  [KEYW]  S. Bradner, "Key words for use in RFCs to Indicate
+          Requirement Levels", RFC 2119, March 1997.
+
+  [LDAP]  M. Wahl, T. Howes, S. Kille, "Lightweight Directory
+          Access Protocol (v3)", RFC 2251, December 1997.
+
+Zeilenga                                                        [Page 6]
+
+INTERNET-DRAFT    LDAP C API Error Reporting Extension 28 September 1999
+
+10.  Author's Address
+
+  Kurt D. Zeilenga
+  OpenLDAP Foundation
+  <Kurt@OpenLDAP.org>
+
+  This document expires on 28 March 2000.
+
+Zeilenga                                                        [Page 7]
diff --git a/doc/man/man3/ldap_dup.3 b/doc/man/man3/ldap_dup.3
new file mode 100644 (file)
index 0000000..252c84c
--- /dev/null
@@ -0,0 +1,126 @@
+.TH LDAP_OPEN 3 "RELEASEDATE" "OpenLDAP LDVERSION"
+.\" $OpenLDAP$
+.\" Copyright 1998-2011 The OpenLDAP Foundation All Rights Reserved.
+.\" Copying restrictions apply.  See COPYRIGHT/LICENSE.
+.SH NAME
+ldap_dup, ldap_destroy, \- Duplicate and destroy LDAP session handles
+.SH LIBRARY
+OpenLDAP LDAP (libldap, \-lldap)
+.SH SYNOPSIS
+.nf
+.ft B
+#include <ldap.h>
+.LP
+.ft B
+LDAP *ldap_dup(
+.RS
+.ft B
+LDAP *\fIold\fB );
+.RE
+.LP
+.ft B
+int ldap_destroy(
+.RS
+.ft B
+LDAP *\fIold\fB );
+.RE
+.SH DESCRIPTION
+.LP
+.B ldap_dup()
+duplicates an existing LDAP
+.RB ( "LDAP *" )
+session handle.
+The new session handle may be used concurrently with the
+original session handle.
+In a threaded environment, different threads may execute concurrent
+requests on the same connection/session without fear of contamination.
+Each session handle manages its own private error results.
+.LP
+.B ldap_destroy()
+destroys an existing session handle.
+.LP
+The
+.B ldap_dup()
+and
+.B ldap_destroy()
+functions are used in conjunction with a "thread safe" version
+of
+.B libldap
+.RB ( libldap_r )
+to enable operation thread safe API calls, so that a single session
+may be simultaneously used across multiple threads with consistent
+error handling.
+.LP
+When a session is created through the use of one of the session creation
+functions including
+.BR ldap_open (3),
+.BR ldap_init (3),
+.BR ldap_initialize (3)
+or
+.BR ldap_init_fd (3)
+an
+.B "LDAP *"
+session handle is returned to the application.
+The session handle may be shared amongst threads, however the
+error codes are unique to a session handle.
+Multiple threads performing different operations using the same
+session handle will result in inconsistent error codes and
+return values.
+.LP
+To prevent this confusion,
+.B ldap_dup()
+is used duplicate an existing session handle so that multiple threads
+can share the session, and maintain consistent error information
+and results.
+.LP
+The message queues for a session are shared between sibling session handles.
+Results of operations on a sibling session handles are accessible
+to all the sibling session handles.
+Applications desiring results associated with a specific operation
+should provide the appropriate msgid to
+.BR ldap_result() .
+Applications should avoid calling
+.B ldap_result()
+with
+.B LDAP_RES_ANY
+as that may "steal" and return results in the calling thread
+that another operation in a different thread, using a
+different session handle, may require to complete.
+.LP
+When
+.B ldap_unbind()
+is called on a session handle with siblings, all the 
+siblings become invalid.
+.LP
+Siblings must be destroyed using
+.BR ldap_destroy() .
+Session handle resources associated with the original
+.RB ( "LDAP *" )
+will be freed when the last session handle is destroyed or when
+.B ldap_unbind()
+is called, if no other session handles currently exist.
+.SH ERRORS
+If an error occurs,
+.B ldap_dup()
+will return NULL and 
+.I errno
+should be set appropriately.
+.B ldap_destroy()
+will directly return the LDAP code associated to the error (or
+.I LDAP_SUCCESS
+in case of success);
+.I errno
+should be set as well whenever appropriate.
+.SH SEE ALSO
+.BR ldap_open (3),
+.BR ldap_init (3),
+.BR ldap_initialize (3),
+.BR ldap_init_fd (3),
+.BR errno (3)
+.SH ACKNOWLEDGEMENTS
+This work is based on the previously proposed
+.B LDAP C API Concurrency Extensions
+draft
+.BR ( draft-zeilenga-ldap-c-api-concurrency-00.txt )
+effort.
+.so ../Project
diff --git a/doc/man/man3/ldap_dup.3.links b/doc/man/man3/ldap_dup.3.links
new file mode 100644 (file)
index 0000000..1d77f93
--- /dev/null
@@ -0,0 +1 @@
+ldap_destroy.3
index 707caa6d62127fee9ad25f76c916ea75f66a47d5..cdf7d91c68eb05ea1a6585f0b64bcb24a8c9e385 100644 (file)
@@ -322,6 +322,15 @@ must be
 the library duplicates the controls passed via
 .BR invalue .
 .TP
+.B LDAP_OPT_SESSION_REFCNT
+Returns the reference count associated with the LDAP handle passed in as
+.BR ld ;
+.BR outvalue
+must be a
+.BR "int *" .
+This is a read-only, handle-specific option.
+This option is OpenLDAP specific.
+.TP
 .B LDAP_OPT_SIZELIMIT
 Sets/gets the value that defines the maximum number of entries
 to be returned by a search operation.
index 85d4fbecca71f1b393a4ba00e205797ef6d7af76..143ee0a5ce8bce1886059b42dbc5c450285173dc 100644 (file)
@@ -59,7 +59,9 @@ LDAP_BEGIN_DECL
                defined( LDAP_API_FEATURE_X_OPENLDAP_THREAD_SAFE ) )
        /* -lldap may or may not be thread safe */
        /* -lldap_r, if available, is always thread safe */
-#      define  LDAP_API_FEATURE_THREAD_SAFE 1
+#      define  LDAP_API_FEATURE_THREAD_SAFE            1
+#      define  LDAP_API_FEATURE_SESSION_THREAD_SAFE    1
+#      define  LDAP_API_FEATURE_OPERATION_THREAD_SAFE  1
 #endif
 #if defined( LDAP_THREAD_SAFE ) && \
        defined( LDAP_API_FEATURE_X_OPENLDAP_THREAD_SAFE )
@@ -135,6 +137,7 @@ LDAP_BEGIN_DECL
 #define LDAP_OPT_DEFBASE               0x5009  /* searchbase */
 #define        LDAP_OPT_CONNECT_ASYNC          0x5010  /* create connections asynchronously */
 #define        LDAP_OPT_CONNECT_CB                     0x5011  /* connection callbacks */
+#define        LDAP_OPT_SESSION_REFCNT         0x5012  /* session reference count */
 
 /* OpenLDAP TLS options */
 #define LDAP_OPT_X_TLS                         0x6000
@@ -1519,6 +1522,10 @@ ldap_initialize LDAP_P((
        LDAP **ldp,
        LDAP_CONST char *url ));
 
+LDAP_F( LDAP * )
+ldap_dup LDAP_P((
+       LDAP *old ));
+
 /*
  * in tls.c
  */
@@ -1931,6 +1938,10 @@ ldap_unbind_ext_s LDAP_P((
        LDAPControl             **serverctrls,
        LDAPControl             **clientctrls));
 
+LDAP_F( int )
+ldap_destroy LDAP_P((
+       LDAP                    *ld));
+
 #if LDAP_DEPRECATED
 LDAP_F( int )
 ldap_unbind LDAP_P(( /* deprecated, use ldap_unbind_ext */
index 4648c3211efc4773ff2eefc34966ec38757c19e8..dd7d4db908bd7565d021aeb77f1ee028a2ee5560 100644 (file)
@@ -69,6 +69,11 @@ typedef pthread_key_t                ldap_int_thread_key_t;
 typedef pthread_rwlock_t ldap_int_thread_rdwr_t;
 #endif
 
+#ifndef LDAP_INT_MUTEX_NULL
+#define LDAP_INT_MUTEX_NULL    PTHREAD_MUTEX_INITIALIZER
+#define LDAP_INT_MUTEX_FIRSTCREATE(m)  ((void) 0)
+#endif
+
 LDAP_END_DECL
 
 #elif defined ( HAVE_MACH_CTHREADS )
@@ -91,6 +96,11 @@ typedef struct mutex         ldap_int_thread_mutex_t;
 typedef struct condition       ldap_int_thread_cond_t;
 typedef cthread_key_t          ldap_int_thread_key_t;
 
+#ifndef LDAP_INT_MUTEX_NULL
+#define LDAP_INT_MUTEX_NULL    MUTEX_INITIALIZER
+#define LDAP_INT_MUTEX_FIRSTCREATE(m)  ((void) 0)
+#endif
+
 LDAP_END_DECL
 
 #elif defined( HAVE_GNU_PTH )
@@ -115,6 +125,11 @@ typedef pth_key_t  ldap_int_thread_key_t;
 typedef pth_rwlock_t ldap_int_thread_rdwr_t;
 #endif
 
+#ifndef LDAP_INT_MUTEX_NULL
+#define LDAP_INT_MUTEX_NULL    PTH_MUTEX_INIT
+#define LDAP_INT_MUTEX_FIRSTCREATE(m)  ((void) 0)
+#endif
+
 LDAP_END_DECL
 
 #elif defined( HAVE_THR )
@@ -143,7 +158,10 @@ typedef thread_key_t       ldap_int_thread_key_t;
 #define LDAP_THREAD_HAVE_SETCONCURRENCY 1
 #endif
 
-LDAP_END_DECL
+#ifndef LDAP_INT_MUTEX_NULL
+#define LDAP_INT_MUTEX_NULL    DEFAULTMUTEX
+#define LDAP_INT_MUTEX_FIRSTCREATE(m)  ((void) 0)
+#endif
 
 #elif defined(HAVE_NT_THREADS)
 /*************************************
@@ -162,6 +180,12 @@ typedef HANDLE     ldap_int_thread_mutex_t;
 typedef HANDLE ldap_int_thread_cond_t;
 typedef DWORD  ldap_int_thread_key_t;
 
+#ifndef LDAP_INT_MUTEX_NULL
+#define LDAP_INT_MUTEX_NULL            ((HANDLE)0)
+#define LDAP_INT_MUTEX_FIRSTCREATE(m) \
+               ((void) ((m) || ldap_int_thread_mutex_init(&(m))))
+#endif
+
 LDAP_END_DECL
 
 #else
@@ -186,6 +210,11 @@ typedef int                        ldap_int_thread_key_t;
 #define LDAP_THREAD_HAVE_TPOOL 1
 typedef int                    ldap_int_thread_pool_t;
 
+#ifndef LDAP_INT_MUTEX_NULL
+#define LDAP_INT_MUTEX_NULL                            0
+#define LDAP_INT_MUTEX_FIRSTCREATE(m)  ((void) 0)
+#endif
+
 LDAP_END_DECL
 
 #endif /* no threads support */
@@ -256,6 +285,10 @@ typedef struct {
        ldap_int_thread_t       owner;
 } ldap_debug_thread_mutex_t;
 
+#define        LDAP_DEBUG_MUTEX_NULL   {LDAP_INT_MUTEX_NULL, {0,0,{0},0} /*,owner*/}
+#define        LDAP_DEBUG_MUTEX_FIRSTCREATE(m) \
+       ((void) ((m).usage.state || ldap_pvt_thread_mutex_init(&(m))))
+
 typedef struct {
        ldap_int_thread_cond_t  wrapped;
        ldap_debug_usage_info_t usage;
index 891fa3e6844a83ef5d9a3b52d46e07bbaad8f81e..d9995df3780b7629da852107de9646aeae1b4758 100644 (file)
@@ -28,10 +28,14 @@ typedef ldap_int_thread_t                   ldap_pvt_thread_t;
 typedef ldap_debug_thread_mutex_t      ldap_pvt_thread_mutex_t;
 typedef ldap_debug_thread_cond_t       ldap_pvt_thread_cond_t;
 typedef ldap_debug_thread_rdwr_t       ldap_pvt_thread_rdwr_t;
+#define LDAP_PVT_MUTEX_FIRSTCREATE     LDAP_DEBUG_MUTEX_FIRSTCREATE
+#define LDAP_PVT_MUTEX_NULL                    LDAP_DEBUG_MUTEX_NULL
 #else
 typedef ldap_int_thread_mutex_t                ldap_pvt_thread_mutex_t;
 typedef ldap_int_thread_cond_t         ldap_pvt_thread_cond_t;
 typedef ldap_int_thread_rdwr_t         ldap_pvt_thread_rdwr_t;
+#define LDAP_PVT_MUTEX_FIRSTCREATE     LDAP_INT_MUTEX_FIRSTCREATE
+#define LDAP_PVT_MUTEX_NULL                    LDAP_INT_MUTEX_NULL
 #endif
 typedef ldap_int_thread_rmutex_t       ldap_pvt_thread_rmutex_t;
 typedef ldap_int_thread_key_t  ldap_pvt_thread_key_t;
index 6618129fc960fa1633de572a4d6e54d82fa489ad..d750b2c34d8d3d97e22353a00bda53fd659596d2 100644 (file)
@@ -206,7 +206,7 @@ start_again:;
                         *              LDAP_NEXT_MSGID(ld, i);
                         */
 
-                       i = ++(ld)->ld_msgid;
+                       LDAP_NEXT_MSGID(ld, i);
 #ifdef LDAP_CONNECTIONLESS
                        if ( LDAP_IS_UDP(ld) ) {
                                struct sockaddr sa = {0};
@@ -216,11 +216,14 @@ start_again:;
                        if ( LDAP_IS_UDP(ld) && ld->ld_options.ldo_version ==
                                LDAP_VERSION2 )
                        {
-                               char *dn = ld->ld_options.ldo_cldapdn;
+                               char *dn;
+                               LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex );
+                               dn = ld->ld_options.ldo_cldapdn;
                                if (!dn) dn = "";
                                err = ber_printf( ber, "{isti",  /* '}' */
                                        i, dn,
                                        LDAP_REQ_ABANDON, msgid );
+                               LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex );
                        } else
 #endif
                        {
@@ -276,7 +279,9 @@ start_again:;
 
        if ( lr != NULL ) {
                if ( sendabandon || lr->lr_status == LDAP_REQST_WRITING ) {
+                       LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
                        ldap_free_connection( ld, lr->lr_conn, 0, 1 );
+                       LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
                }
 
                if ( origid == msgid ) {
@@ -287,10 +292,7 @@ start_again:;
                }
        }
 
-       /* ld_abandoned is actually protected by the ld_res_mutex;
-        * give up the ld_req_mutex and get the other */
-       LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
-       LDAP_MUTEX_LOCK( &ld->ld_res_mutex );
+       LDAP_MUTEX_LOCK( &ld->ld_abandon_mutex );
 
        /* use bisection */
        i = 0;
@@ -304,8 +306,7 @@ start_again:;
                ld->ld_errno = LDAP_SUCCESS;
        }
 
-       LDAP_MUTEX_UNLOCK( &ld->ld_res_mutex );
-       LDAP_MUTEX_LOCK( &ld->ld_req_mutex );
+       LDAP_MUTEX_UNLOCK( &ld->ld_abandon_mutex );
        return( ld->ld_errno );
 }
 
@@ -446,4 +447,3 @@ ldap_int_bisect_delete( ber_int_t **vp, ber_len_t *np, int id, int idx )
 
        return 0;
 }
-
index 24417b9809208d1a150394bd706ab4ef070c663e..52a04d7a4cbdc9220f50bedf3e883840db9a8c33 100644 (file)
@@ -416,7 +416,7 @@ ldap_int_sasl_bind(
                void    *ssl;
 
                rc = 0;
-               LDAP_MUTEX_LOCK( &ld->ld_req_mutex );
+               LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
                ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, &sd );
 
                if ( sd == AC_SOCKET_INVALID ) {
@@ -434,7 +434,7 @@ ldap_int_sasl_bind(
                                }
                        }
                }   
-               LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
+               LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
                if( rc != 0 ) return ld->ld_errno;
 
                oldctx = ld->ld_defconn->lconn_sasl_authctx;
@@ -1205,7 +1205,10 @@ ldap_int_sasl_bind(
        LDAPControl             **cctrls,
        unsigned                flags,
        LDAP_SASL_INTERACT_PROC *interact,
-       void * defaults )
+       void                    *defaults,
+       LDAPMessage             *result,
+       const char              **rmech,
+       int                             *msgid )
 { return LDAP_NOT_SUPPORTED; }
 
 int
index 2e8fb21d54152c3a530b5ddaf559de1053794fa0..fc8d7ee55854b0149bba4c0e71435bfbfa94c928 100644 (file)
@@ -664,9 +664,7 @@ ldap_int_gss_spnego_bind_s( LDAP *ld )
        gss_buffer_desc input_token, output_token = GSS_C_EMPTY_BUFFER;
        struct berval cred, *scred = NULL;
 
-#ifdef LDAP_R_COMPILE
-       ldap_pvt_thread_mutex_lock( &ldap_int_gssapi_mutex );
-#endif
+       LDAP_MUTEX_LOCK( &ldap_int_gssapi_mutex );
 
        /* get information from RootDSE entry */
        rc = ldap_gssapi_get_rootdse_infos ( ld, &mechlist,
@@ -784,9 +782,7 @@ gss_error:
                              (ret_mech != GSS_C_NO_OID ? ret_mech : req_mech ),
                              gss_rc, minor_status );
 rc_error:
-#ifdef LDAP_R_COMPILE
-       ldap_pvt_thread_mutex_unlock( &ldap_int_gssapi_mutex );
-#endif
+       LDAP_MUTEX_UNLOCK( &ldap_int_gssapi_mutex );
        LDAP_FREE( mechlist );
        LDAP_FREE( ldapServiceName );
        LDAP_FREE( dnsHostName );
index 89de84aa5b8a96af1e94e7af1e23e8410d35442f..3355b4c8dcb3ee05428ff25697ce4e8a35c7dfa7 100644 (file)
@@ -36,7 +36,7 @@
 #include "lutil.h"
 
 struct ldapoptions ldap_int_global_options =
-       { LDAP_UNINITIALIZED, LDAP_DEBUG_NONE };  
+       { LDAP_UNINITIALIZED, LDAP_DEBUG_NONE LDAP_LDO_MUTEX_NULLARG };  
 
 #define ATTR_NONE      0
 #define ATTR_BOOL      1
@@ -510,6 +510,13 @@ ldap_int_destroy_global_options(void)
  */
 void ldap_int_initialize_global_options( struct ldapoptions *gopts, int *dbglvl )
 {
+       LDAP_PVT_MUTEX_FIRSTCREATE(gopts->ldo_mutex);
+       LDAP_MUTEX_LOCK( &gopts->ldo_mutex );
+       if (gopts->ldo_valid == LDAP_INITIALIZED) {
+               /* someone else got here first */
+               LDAP_MUTEX_UNLOCK( &gopts->ldo_mutex );
+               return;
+       }
        if (dbglvl)
            gopts->ldo_debug = *dbglvl;
        else
@@ -573,6 +580,7 @@ void ldap_int_initialize_global_options( struct ldapoptions *gopts, int *dbglvl
        gopts->ldo_keepalive_idle = 0;
 
        gopts->ldo_valid = LDAP_INITIALIZED;
+       LDAP_MUTEX_UNLOCK( &gopts->ldo_mutex );
        return;
 }
 
index 984613605223121d1ed700c83f7b66db4ff9455d..9bbd056dc4e9dec0e1e123a876d9cd4f08dcd5f2 100644 (file)
@@ -174,6 +174,7 @@ typedef struct ldaplist {
 /*
  * structure representing get/set'able options
  * which have global defaults.
+ * Protect access to this struct with ldo_mutex
  */
 struct ldapoptions {
        short ldo_valid;
@@ -182,6 +183,15 @@ struct ldapoptions {
 #define LDAP_VALID_SESSION     0x2
 #define LDAP_TRASHED_SESSION   0xFF
        int   ldo_debug;
+
+#ifdef LDAP_R_COMPILE
+       ldap_pvt_thread_mutex_t ldo_mutex;
+#define LDAP_LDO_MUTEX_NULLARG , LDAP_PVT_MUTEX_NULL
+#else
+#define LDAP_LDO_MUTEX_NULLARG
+#define LDAP_PVT_MUTEX_FIRSTCREATE(m)  ((void) 0)
+#endif
+
 #ifdef LDAP_CONNECTIONLESS
 #define        LDAP_IS_UDP(ld)         ((ld)->ld_options.ldo_is_udp)
        void*                   ldo_peer;       /* struct sockaddr* */
@@ -361,24 +371,27 @@ typedef struct ldapreqinfo {
  * structure representing an ldap connection
  */
 
-struct ldap {
-       Sockbuf         *ld_sb;         /* socket descriptor & buffer */
+struct ldap_common {
+       Sockbuf         *ldc_sb;        /* socket descriptor & buffer */
+#define ld_sb                  ldc->ldc_sb
 
-       struct ldapoptions ld_options;
+       /* protected by ldo_mutex */
+       struct ldapoptions ldc_options;
+#define ld_options             ldc->ldc_options
 
 #define ld_valid               ld_options.ldo_valid
 #define ld_debug               ld_options.ldo_debug
 
 #define ld_deref               ld_options.ldo_deref
-#define ld_timelimit   ld_options.ldo_timelimit
-#define ld_sizelimit   ld_options.ldo_sizelimit
+#define ld_timelimit           ld_options.ldo_timelimit
+#define ld_sizelimit           ld_options.ldo_sizelimit
 
-#define ld_defbinddn   ld_options.ldo_defbinddn
+#define ld_defbinddn           ld_options.ldo_defbinddn
 #define ld_defbase             ld_options.ldo_defbase
 #define ld_defhost             ld_options.ldo_defhost
 #define ld_defport             ld_options.ldo_defport
 
-#define ld_refhoplimit ld_options.ldo_refhoplimit
+#define ld_refhoplimit         ld_options.ldo_refhoplimit
 
 #define ld_sctrls              ld_options.ldo_sctrls
 #define ld_cctrls              ld_options.ldo_cctrls
@@ -390,36 +403,79 @@ struct ldap {
 #define ld_urllist_params      ld_options.ldo_urllist_params
 
 #define ld_version             ld_options.ldo_version
+#ifdef LDAP_R_COMPILE
+#define        ld_ldopts_mutex         ld_options.ldo_mutex
+#endif
 
-       unsigned short  ld_lberoptions;
+       unsigned short  ldc_lberoptions;
+#define        ld_lberoptions          ldc->ldc_lberoptions
 
-       ber_int_t       ld_errno;
-       char    *ld_error;
-       char    *ld_matched;
-       char    **ld_referrals;
-       ber_len_t               ld_msgid;
+       /* protected by msgid_mutex */
+       ber_len_t               ldc_msgid;
+#define        ld_msgid                ldc->ldc_msgid
 
        /* do not mess with these */
-       LDAPRequest     *ld_requests;   /* list of outstanding requests */
-       LDAPMessage     *ld_responses;  /* list of outstanding responses */
+       /* protected by req_mutex */
+       LDAPRequest     *ldc_requests;  /* list of outstanding requests */
+       /* protected by res_mutex */
+       LDAPMessage     *ldc_responses; /* list of outstanding responses */
+#define        ld_requests             ldc->ldc_requests
+#define        ld_responses            ldc->ldc_responses
 
 #ifdef LDAP_R_COMPILE
-       ldap_pvt_thread_mutex_t ld_conn_mutex;
-       ldap_pvt_thread_mutex_t ld_req_mutex;
-       ldap_pvt_thread_mutex_t ld_res_mutex;
+       ldap_pvt_thread_mutex_t ldc_msgid_mutex;
+       ldap_pvt_thread_mutex_t ldc_conn_mutex;
+       ldap_pvt_thread_mutex_t ldc_req_mutex;
+       ldap_pvt_thread_mutex_t ldc_res_mutex;
+       ldap_pvt_thread_mutex_t ldc_abandon_mutex;
+#define        ld_msgid_mutex          ldc->ldc_msgid_mutex
+#define        ld_conn_mutex           ldc->ldc_conn_mutex
+#define        ld_req_mutex            ldc->ldc_req_mutex
+#define        ld_res_mutex            ldc->ldc_res_mutex
+#define        ld_abandon_mutex        ldc->ldc_abandon_mutex
 #endif
 
-       ber_len_t       ld_nabandoned;
-       ber_int_t       *ld_abandoned;  /* array of abandoned requests */
+       /* protected by abandon_mutex */
+       ber_len_t       ldc_nabandoned;
+       ber_int_t       *ldc_abandoned; /* array of abandoned requests */
+#define        ld_nabandoned           ldc->ldc_nabandoned
+#define        ld_abandoned            ldc->ldc_abandoned
 
-       LDAPCache       *ld_cache;      /* non-null if cache is initialized */
+       /* unused by libldap */
+       LDAPCache       *ldc_cache;     /* non-null if cache is initialized */
+#define        ld_cache                ldc->ldc_cache
 
        /* do not mess with the rest though */
 
-       LDAPConn        *ld_defconn;    /* default connection */
-       LDAPConn        *ld_conns;      /* list of server connections */
-       void            *ld_selectinfo; /* platform specifics for select */
+       /* protected by conn_mutex */
+       LDAPConn        *ldc_defconn;   /* default connection */
+#define        ld_defconn              ldc->ldc_defconn
+       LDAPConn        *ldc_conns;     /* list of server connections */
+#define        ld_conns                ldc->ldc_conns
+       void            *ldc_selectinfo;/* platform specifics for select */
+#define        ld_selectinfo           ldc->ldc_selectinfo
+
+       /* ldap_common refcnt - free only if 0 */
+#ifdef LDAP_R_COMPILE
+       ldap_pvt_thread_mutex_t ldc_mutex;
+#define        ld_ldcmutex             ldc->ldc_mutex
+#endif
+       /* protected by ldc_mutex */
+       unsigned int            ldc_refcnt;
+#define        ld_ldcrefcnt            ldc->ldc_refcnt
+};
+
+struct ldap {
+       /* thread shared */
+       struct ldap_common      *ldc;
+
+       /* thread specific */
+       ber_int_t               ld_errno;
+       char                    *ld_error;
+       char                    *ld_matched;
+       char                    **ld_referrals;
 };
+
 #define LDAP_VALID(ld)         ( (ld)->ld_valid == LDAP_VALID_SESSION )
 #define LDAP_TRASHED(ld)       ( (ld)->ld_valid == LDAP_TRASHED_SESSION )
 #define LDAP_TRASH(ld)         ( (ld)->ld_valid = LDAP_TRASHED_SESSION )
@@ -441,19 +497,16 @@ LDAP_V( ldap_pvt_thread_mutex_t ) ldap_int_gssapi_mutex;
 #define LDAP_ASSERT_MUTEX_OWNER(mutex) \
        LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER(mutex)
 #else
-#define LDAP_MUTEX_LOCK(mutex)
-#define LDAP_MUTEX_UNLOCK(mutex)
-#define LDAP_ASSERT_MUTEX_OWNER(mutex)
+#define LDAP_MUTEX_LOCK(mutex)    ((void) 0)
+#define LDAP_MUTEX_UNLOCK(mutex)  ((void) 0)
+#define LDAP_ASSERT_MUTEX_OWNER(mutex) ((void) 0)
 #endif
 
-#ifdef LDAP_R_COMPILE
-#define        LDAP_NEXT_MSGID(ld, id) \
-       LDAP_MUTEX_LOCK( &(ld)->ld_req_mutex ); \
-       id = ++(ld)->ld_msgid; \
-       LDAP_MUTEX_UNLOCK( &(ld)->ld_req_mutex )
-#else
-#define        LDAP_NEXT_MSGID(ld, id) id = ++(ld)->ld_msgid
-#endif
+#define        LDAP_NEXT_MSGID(ld, id) do { \
+       LDAP_MUTEX_LOCK( &(ld)->ld_msgid_mutex ); \
+       (id) = ++(ld)->ld_msgid; \
+       LDAP_MUTEX_UNLOCK( &(ld)->ld_msgid_mutex ); \
+} while (0)
 
 /*
  * in abandon.c
@@ -592,8 +645,11 @@ LDAP_F (ber_int_t) ldap_send_initial_request( LDAP *ld, ber_tag_t msgtype,
 LDAP_F (BerElement *) ldap_alloc_ber_with_options( LDAP *ld );
 LDAP_F (void) ldap_set_ber_options( LDAP *ld, BerElement *ber );
 
-LDAP_F (int) ldap_send_server_request( LDAP *ld, BerElement *ber, ber_int_t msgid, LDAPRequest *parentreq, LDAPURLDesc **srvlist, LDAPConn *lc, LDAPreqinfo *bind );
-LDAP_F (LDAPConn *) ldap_new_connection( LDAP *ld, LDAPURLDesc **srvlist, int use_ldsb, int connect, LDAPreqinfo *bind );
+LDAP_F (int) ldap_send_server_request( LDAP *ld, BerElement *ber,
+       ber_int_t msgid, LDAPRequest *parentreq, LDAPURLDesc **srvlist,
+       LDAPConn *lc, LDAPreqinfo *bind, int noconn, int m_res );
+LDAP_F (LDAPConn *) ldap_new_connection( LDAP *ld, LDAPURLDesc **srvlist,
+       int use_ldsb, int connect, LDAPreqinfo *bind, int m_req, int m_res );
 LDAP_F (LDAPRequest *) ldap_find_request_by_msgid( LDAP *ld, ber_int_t msgid );
 LDAP_F (void) ldap_return_request( LDAP *ld, LDAPRequest *lr, int freeit );
 LDAP_F (void) ldap_free_request( LDAP *ld, LDAPRequest *lr );
index db5eacc69ffc5fbcd5b7dca6f9f4f726b2b8c58a..5cc653139f5442ac309670d9ab00ad048416f114 100644 (file)
 #include "ldap-int.h"
 #include "ldap_log.h"
 
-/* Caller should hold the req_mutex if simultaneous accesses are possible */
+/* Caller must hold the conn_mutex since simultaneous accesses are possible */
 int ldap_open_defconn( LDAP *ld )
 {
        ld->ld_defconn = ldap_new_connection( ld,
-               &ld->ld_options.ldo_defludp, 1, 1, NULL );
+               &ld->ld_options.ldo_defludp, 1, 1, NULL, 0, 0 );
 
        if( ld->ld_defconn == NULL ) {
                ld->ld_errno = LDAP_SERVER_DOWN;
@@ -74,7 +74,9 @@ ldap_open( LDAP_CONST char *host, int port )
                return( NULL );
        }
 
+       LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
        rc = ldap_open_defconn( ld );
+       LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
 
        if( rc < 0 ) {
                ldap_ld_free( ld, 0, NULL, NULL );
@@ -114,8 +116,19 @@ ldap_create( LDAP **ldp )
                return( LDAP_NO_MEMORY );
        }
    
+       if ( (ld->ldc = (struct ldap_common *) LDAP_CALLOC( 1,
+                       sizeof(struct ldap_common) )) == NULL ) {
+               LDAP_FREE( (char *)ld );
+               return( LDAP_NO_MEMORY );
+       }
        /* copy the global options */
+       LDAP_MUTEX_LOCK( &gopts->ldo_mutex );
        AC_MEMCPY(&ld->ld_options, gopts, sizeof(ld->ld_options));
+#ifdef LDAP_R_COMPILE
+       /* Properly initialize the structs mutex */
+       ldap_pvt_thread_mutex_init( &(ld->ld_ldopts_mutex) );
+#endif
+       LDAP_MUTEX_UNLOCK( &gopts->ldo_mutex );
 
        ld->ld_valid = LDAP_VALID_SESSION;
 
@@ -159,10 +172,14 @@ ldap_create( LDAP **ldp )
        if ( ld->ld_sb == NULL ) goto nomem;
 
 #ifdef LDAP_R_COMPILE
+       ldap_pvt_thread_mutex_init( &ld->ld_msgid_mutex );
+       ldap_pvt_thread_mutex_init( &ld->ld_conn_mutex );
        ldap_pvt_thread_mutex_init( &ld->ld_req_mutex );
        ldap_pvt_thread_mutex_init( &ld->ld_res_mutex );
-       ldap_pvt_thread_mutex_init( &ld->ld_conn_mutex );
+       ldap_pvt_thread_mutex_init( &ld->ld_abandon_mutex );
+       ldap_pvt_thread_mutex_init( &ld->ld_ldcmutex );
 #endif
+       ld->ld_ldcrefcnt = 1;
        *ldp = ld;
        return LDAP_SUCCESS;
 
@@ -265,8 +282,9 @@ ldap_init_fd(
                }
        }
 
+       LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
        /* Attach the passed socket as the LDAP's connection */
-       conn = ldap_new_connection( ld, NULL, 1, 0, NULL);
+       conn = ldap_new_connection( ld, NULL, 1, 0, NULL, 0, 0 );
        if( conn == NULL ) {
                ldap_unbind_ext( ld, NULL, NULL );
                return( LDAP_NO_MEMORY );
@@ -276,6 +294,7 @@ ldap_init_fd(
        ber_sockbuf_ctrl( conn->lconn_sb, LBER_SB_OPT_SET_FD, &fd );
        ld->ld_defconn = conn;
        ++ld->ld_defconn->lconn_refcnt; /* so it never gets closed/freed */
+       LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
 
        switch( proto ) {
        case LDAP_PROTO_TCP:
@@ -331,6 +350,7 @@ ldap_init_fd(
        return LDAP_SUCCESS;
 }
 
+/* Protected by ld_conn_mutex */
 int
 ldap_int_open_connection(
        LDAP *ld,
@@ -434,8 +454,9 @@ ldap_open_internal_connection( LDAP **ldp, ber_socket_t *fdp )
        int rc;
        LDAPConn *c;
        LDAPRequest *lr;
+       LDAP    *ld;
 
-       rc = ldap_create( ldp );
+       rc = ldap_create( &ld );
        if( rc != LDAP_SUCCESS ) {
                *ldp = NULL;
                return( rc );
@@ -444,7 +465,7 @@ ldap_open_internal_connection( LDAP **ldp, ber_socket_t *fdp )
        /* Make it appear that a search request, msgid 0, was sent */
        lr = (LDAPRequest *)LDAP_CALLOC( 1, sizeof( LDAPRequest ));
        if( lr == NULL ) {
-               ldap_unbind_ext( *ldp, NULL, NULL );
+               ldap_unbind_ext( ld, NULL, NULL );
                *ldp = NULL;
                return( LDAP_NO_MEMORY );
        }
@@ -453,13 +474,15 @@ ldap_open_internal_connection( LDAP **ldp, ber_socket_t *fdp )
        lr->lr_status = LDAP_REQST_INPROGRESS;
        lr->lr_res_errno = LDAP_SUCCESS;
        /* no mutex lock needed, we just created this ld here */
-       (*ldp)->ld_requests = lr;
+       ld->ld_requests = lr;
 
+       LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
        /* Attach the passed socket as the *LDAP's connection */
-       c = ldap_new_connection( *ldp, NULL, 1, 0, NULL);
+       c = ldap_new_connection( ld, NULL, 1, 0, NULL, 0, 0 );
        if( c == NULL ) {
-               ldap_unbind_ext( *ldp, NULL, NULL );
+               ldap_unbind_ext( ld, NULL, NULL );
                *ldp = NULL;
+               LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
                return( LDAP_NO_MEMORY );
        }
        ber_sockbuf_ctrl( c->lconn_sb, LBER_SB_OPT_SET_FD, fdp );
@@ -469,15 +492,39 @@ ldap_open_internal_connection( LDAP **ldp, ber_socket_t *fdp )
 #endif
        ber_sockbuf_add_io( c->lconn_sb, &ber_sockbuf_io_tcp,
          LBER_SBIOD_LEVEL_PROVIDER, NULL );
-       (*ldp)->ld_defconn = c;
+       ld->ld_defconn = c;
+       LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
 
        /* Add the connection to the *LDAP's select pool */
-       ldap_mark_select_read( *ldp, c->lconn_sb );
-       ldap_mark_select_write( *ldp, c->lconn_sb );
+       ldap_mark_select_read( ld, c->lconn_sb );
+       ldap_mark_select_write( ld, c->lconn_sb );
 
        /* Make this connection an LDAP V3 protocol connection */
        rc = LDAP_VERSION3;
-       ldap_set_option( *ldp, LDAP_OPT_PROTOCOL_VERSION, &rc );
+       ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &rc );
+       *ldp = ld;
 
        return( LDAP_SUCCESS );
 }
+
+LDAP *
+ldap_dup( LDAP *old )
+{
+       LDAP                    *ld;
+
+       if ( old == NULL ) {
+               return( NULL );
+       }
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_dup\n", 0, 0, 0 );
+
+       if ( (ld = (LDAP *) LDAP_CALLOC( 1, sizeof(LDAP) )) == NULL ) {
+               return( NULL );
+       }
+   
+       LDAP_MUTEX_LOCK( &old->ld_ldcmutex );
+       ld->ldc = old->ldc;
+       old->ld_ldcrefcnt++;
+       LDAP_MUTEX_UNLOCK( &old->ld_ldcmutex );
+       return ( ld );
+}
index e6e8496bb4f05cf081222ebb42b3fe7f937f0857..eec7c6df611e23af68a89462127a8dbd471af5ff 100644 (file)
@@ -96,6 +96,7 @@ ldap_get_option(
        void    *outvalue)
 {
        struct ldapoptions *lo;
+       int rc = LDAP_OPT_ERROR;
 
        /* Get pointer to global option structure */
        lo = LDAP_INT_GLOBAL_OPT();   
@@ -122,19 +123,21 @@ ldap_get_option(
                return LDAP_OPT_ERROR;
        }
 
+       LDAP_MUTEX_LOCK( &lo->ldo_mutex );
+
        switch(option) {
        case LDAP_OPT_API_INFO: {
                        struct ldapapiinfo *info = (struct ldapapiinfo *) outvalue;
 
                        if(info == NULL) {
                                /* outvalue must point to an apiinfo structure */
-                               return LDAP_OPT_ERROR;
+                               break;  /* LDAP_OPT_ERROR */
                        }
 
                        if(info->ldapai_info_version != LDAP_API_INFO_VERSION) {
                                /* api info version mismatch */
                                info->ldapai_info_version = LDAP_API_INFO_VERSION;
-                               return LDAP_OPT_ERROR;
+                               break;  /* LDAP_OPT_ERROR */
                        }
 
                        info->ldapai_api_version = LDAP_API_VERSION;
@@ -158,7 +161,8 @@ ldap_get_option(
                        info->ldapai_vendor_name = LDAP_STRDUP(LDAP_VENDOR_NAME);
                        info->ldapai_vendor_version = LDAP_VENDOR_VERSION;
 
-                       return LDAP_OPT_SUCCESS;
+                       rc = LDAP_OPT_SUCCESS;
+                       break;
                } break;
 
        case LDAP_OPT_DESC:
@@ -168,74 +172,86 @@ ldap_get_option(
                } 
 
                ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, outvalue );
-               return LDAP_OPT_SUCCESS;
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        case LDAP_OPT_SOCKBUF:
                if( ld == NULL ) break;
                *(Sockbuf **)outvalue = ld->ld_sb;
-               return LDAP_OPT_SUCCESS;
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        case LDAP_OPT_TIMEOUT:
                /* the caller has to free outvalue ! */
                if ( lo->ldo_tm_api.tv_sec < 0 ) {
                        *(void **)outvalue = NULL;
                } else if ( ldap_int_timeval_dup( outvalue, &lo->ldo_tm_api ) != 0 ) {
-                       return LDAP_OPT_ERROR;
+                       break;  /* LDAP_OPT_ERROR */
                }
-               return LDAP_OPT_SUCCESS;
+               rc = LDAP_OPT_SUCCESS;
+               break;
                
        case LDAP_OPT_NETWORK_TIMEOUT:
                /* the caller has to free outvalue ! */
                if ( lo->ldo_tm_net.tv_sec < 0 ) {
                        *(void **)outvalue = NULL;
                } else if ( ldap_int_timeval_dup( outvalue, &lo->ldo_tm_net ) != 0 ) {
-                       return LDAP_OPT_ERROR;
+                       break;  /* LDAP_OPT_ERROR */
                }
-               return LDAP_OPT_SUCCESS;
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        case LDAP_OPT_DEREF:
                * (int *) outvalue = lo->ldo_deref;
-               return LDAP_OPT_SUCCESS;
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        case LDAP_OPT_SIZELIMIT:
                * (int *) outvalue = lo->ldo_sizelimit;
-               return LDAP_OPT_SUCCESS;
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        case LDAP_OPT_TIMELIMIT:
                * (int *) outvalue = lo->ldo_timelimit;
-               return LDAP_OPT_SUCCESS;
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        case LDAP_OPT_REFERRALS:
                * (int *) outvalue = (int) LDAP_BOOL_GET(lo, LDAP_BOOL_REFERRALS);
-               return LDAP_OPT_SUCCESS;
+               rc = LDAP_OPT_SUCCESS;
+               break;
                
        case LDAP_OPT_RESTART:
                * (int *) outvalue = (int) LDAP_BOOL_GET(lo, LDAP_BOOL_RESTART);
-               return LDAP_OPT_SUCCESS;
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        case LDAP_OPT_PROTOCOL_VERSION:
                * (int *) outvalue = lo->ldo_version;
-               return LDAP_OPT_SUCCESS;
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        case LDAP_OPT_SERVER_CONTROLS:
                * (LDAPControl ***) outvalue =
                        ldap_controls_dup( lo->ldo_sctrls );
-
-               return LDAP_OPT_SUCCESS;
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        case LDAP_OPT_CLIENT_CONTROLS:
                * (LDAPControl ***) outvalue =
                        ldap_controls_dup( lo->ldo_cctrls );
-
-               return LDAP_OPT_SUCCESS;
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        case LDAP_OPT_HOST_NAME:
                * (char **) outvalue = ldap_url_list2hosts(lo->ldo_defludp);
-               return LDAP_OPT_SUCCESS;
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        case LDAP_OPT_URI:
                * (char **) outvalue = ldap_url_list2urls(lo->ldo_defludp);
-               return LDAP_OPT_SUCCESS;
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        case LDAP_OPT_DEFBASE:
                if( lo->ldo_defbase == NULL ) {
@@ -243,12 +259,13 @@ ldap_get_option(
                } else {
                        * (char **) outvalue = LDAP_STRDUP(lo->ldo_defbase);
                }
-
-               return LDAP_OPT_SUCCESS;
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        case LDAP_OPT_CONNECT_ASYNC:
                * (int *) outvalue = (int) LDAP_BOOL_GET(lo, LDAP_BOOL_CONNECT_ASYNC);
-               return LDAP_OPT_SUCCESS;
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        case LDAP_OPT_CONNECT_CB:
                {
@@ -263,7 +280,8 @@ ldap_get_option(
                                }
                        }
                }
-               return LDAP_OPT_SUCCESS;
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        case LDAP_OPT_RESULT_CODE:
                if(ld == NULL) {
@@ -271,7 +289,8 @@ ldap_get_option(
                        break;
                } 
                * (int *) outvalue = ld->ld_errno;
-               return LDAP_OPT_SUCCESS;
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        case LDAP_OPT_DIAGNOSTIC_MESSAGE:
                if(ld == NULL) {
@@ -284,8 +303,8 @@ ldap_get_option(
                } else {
                        * (char **) outvalue = LDAP_STRDUP(ld->ld_error);
                }
-
-               return LDAP_OPT_SUCCESS;
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        case LDAP_OPT_MATCHED_DN:
                if(ld == NULL) {
@@ -298,8 +317,8 @@ ldap_get_option(
                } else {
                        * (char **) outvalue = LDAP_STRDUP( ld->ld_matched );
                }
-
-               return LDAP_OPT_SUCCESS;
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        case LDAP_OPT_REFERRAL_URLS:
                if(ld == NULL) {
@@ -312,28 +331,31 @@ ldap_get_option(
                } else {
                        * (char ***) outvalue = ldap_value_dup(ld->ld_referrals);
                }
-
-               return LDAP_OPT_SUCCESS;
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        case LDAP_OPT_API_FEATURE_INFO: {
                        LDAPAPIFeatureInfo *info = (LDAPAPIFeatureInfo *) outvalue;
                        int i;
 
-                       if(info == NULL) return LDAP_OPT_ERROR;
+                       if(info == NULL)
+                               break;  /* LDAP_OPT_ERROR */
 
                        if(info->ldapaif_info_version != LDAP_FEATURE_INFO_VERSION) {
                                /* api info version mismatch */
                                info->ldapaif_info_version = LDAP_FEATURE_INFO_VERSION;
-                               return LDAP_OPT_ERROR;
+                               break;  /* LDAP_OPT_ERROR */
                        }
 
-                       if(info->ldapaif_name == NULL) return LDAP_OPT_ERROR;
+                       if(info->ldapaif_name == NULL)
+                               break;  /* LDAP_OPT_ERROR */
 
                        for(i=0; features[i].ldapaif_name != NULL; i++) {
                                if(!strcmp(info->ldapaif_name, features[i].ldapaif_name)) {
                                        info->ldapaif_version =
                                                features[i].ldapaif_version;
-                                       return LDAP_OPT_SUCCESS;
+                                       rc = LDAP_OPT_SUCCESS;
+                                       break;
                                }
                        }
                }
@@ -341,41 +363,54 @@ ldap_get_option(
 
        case LDAP_OPT_DEBUG_LEVEL:
                * (int *) outvalue = lo->ldo_debug;
-               return LDAP_OPT_SUCCESS;
+               rc = LDAP_OPT_SUCCESS;
+               break;
        
+       case LDAP_OPT_SESSION_REFCNT:
+               * (int *) outvalue = ld->ld_ldcrefcnt;
+               rc = LDAP_OPT_SUCCESS;
+               break;
+
        case LDAP_OPT_X_KEEPALIVE_IDLE:
                * (int *) outvalue = lo->ldo_keepalive_idle;
-               return LDAP_OPT_SUCCESS;
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        case LDAP_OPT_X_KEEPALIVE_PROBES:
                * (int *) outvalue = lo->ldo_keepalive_probes;
-               return LDAP_OPT_SUCCESS;
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        case LDAP_OPT_X_KEEPALIVE_INTERVAL:
                * (int *) outvalue = lo->ldo_keepalive_interval;
-               return LDAP_OPT_SUCCESS;
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        default:
 #ifdef HAVE_TLS
                if ( ldap_pvt_tls_get_option( ld, option, outvalue ) == 0 ) {
-                       return LDAP_OPT_SUCCESS;
+                       rc = LDAP_OPT_SUCCESS;
+                       break;
                }
 #endif
 #ifdef HAVE_CYRUS_SASL
                if ( ldap_int_sasl_get_option( ld, option, outvalue ) == 0 ) {
-                       return LDAP_OPT_SUCCESS;
+                       rc = LDAP_OPT_SUCCESS;
+                       break;
                }
 #endif
 #ifdef HAVE_GSSAPI
                if ( ldap_int_gssapi_get_option( ld, option, outvalue ) == 0 ) {
-                       return LDAP_OPT_SUCCESS;
+                       rc = LDAP_OPT_SUCCESS;
+                       break;
                }
 #endif
                /* bad param */
                break;
        }
 
-       return LDAP_OPT_ERROR;
+       LDAP_MUTEX_UNLOCK( &lo->ldo_mutex );
+       return ( rc );
 }
 
 int
@@ -386,6 +421,7 @@ ldap_set_option(
 {
        struct ldapoptions *lo;
        int *dbglvl = NULL;
+       int rc = LDAP_OPT_ERROR;
 
        /* Get pointer to global option structure */
        lo = LDAP_INT_GLOBAL_OPT();
@@ -416,14 +452,19 @@ ldap_set_option(
                lo = &ld->ld_options;
        }
 
-       switch(option) {
+       LDAP_MUTEX_LOCK( &lo->ldo_mutex );
+
+       switch ( option ) {
+
+       /* options with boolean values */
        case LDAP_OPT_REFERRALS:
                if(invalue == LDAP_OPT_OFF) {
                        LDAP_BOOL_CLR(lo, LDAP_BOOL_REFERRALS);
                } else {
                        LDAP_BOOL_SET(lo, LDAP_BOOL_REFERRALS);
                }
-               return LDAP_OPT_SUCCESS;
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        case LDAP_OPT_RESTART:
                if(invalue == LDAP_OPT_OFF) {
@@ -431,7 +472,8 @@ ldap_set_option(
                } else {
                        LDAP_BOOL_SET(lo, LDAP_BOOL_RESTART);
                }
-               return LDAP_OPT_SUCCESS;
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        case LDAP_OPT_CONNECT_ASYNC:
                if(invalue == LDAP_OPT_OFF) {
@@ -439,11 +481,10 @@ ldap_set_option(
                } else {
                        LDAP_BOOL_SET(lo, LDAP_BOOL_CONNECT_ASYNC);
                }
-               return LDAP_OPT_SUCCESS;
-       }
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        /* options which can withstand invalue == NULL */
-       switch ( option ) {
        case LDAP_OPT_SERVER_CONTROLS: {
                        LDAPControl *const *controls =
                                (LDAPControl *const *) invalue;
@@ -453,16 +494,19 @@ ldap_set_option(
 
                        if( controls == NULL || *controls == NULL ) {
                                lo->ldo_sctrls = NULL;
-                               return LDAP_OPT_SUCCESS;
+                               rc = LDAP_OPT_SUCCESS;
+                               break;
                        }
                                
                        lo->ldo_sctrls = ldap_controls_dup( controls );
 
                        if(lo->ldo_sctrls == NULL) {
                                /* memory allocation error ? */
-                               break;
+                               break;  /* LDAP_OPT_ERROR */
                        }
-               } return LDAP_OPT_SUCCESS;
+               }
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        case LDAP_OPT_CLIENT_CONTROLS: {
                        LDAPControl *const *controls =
@@ -473,22 +517,25 @@ ldap_set_option(
 
                        if( controls == NULL || *controls == NULL ) {
                                lo->ldo_cctrls = NULL;
-                               return LDAP_OPT_SUCCESS;
+                               rc = LDAP_OPT_SUCCESS;
+                               break;
                        }
                                
                        lo->ldo_cctrls = ldap_controls_dup( controls );
 
                        if(lo->ldo_cctrls == NULL) {
                                /* memory allocation error ? */
-                               break;
+                               break;  /* LDAP_OPT_ERROR */
                        }
-               } return LDAP_OPT_SUCCESS;
+               }
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
 
        case LDAP_OPT_HOST_NAME: {
                        const char *host = (const char *) invalue;
                        LDAPURLDesc *ludlist = NULL;
-                       int rc = LDAP_OPT_SUCCESS;
+                       rc = LDAP_OPT_SUCCESS;
 
                        if(host != NULL) {
                                rc = ldap_url_parsehosts( &ludlist, host,
@@ -519,13 +566,13 @@ ldap_set_option(
                                        ldap_free_urllist(lo->ldo_defludp);
                                lo->ldo_defludp = ludlist;
                        }
-                       return rc;
+                       break;
                }
 
        case LDAP_OPT_URI: {
                        const char *urls = (const char *) invalue;
                        LDAPURLDesc *ludlist = NULL;
-                       int rc = LDAP_OPT_SUCCESS;
+                       rc = LDAP_OPT_SUCCESS;
 
                        if(urls != NULL) {
                                rc = ldap_url_parselist_ext(&ludlist, urls, NULL,
@@ -578,7 +625,7 @@ ldap_set_option(
                                        ldap_free_urllist(lo->ldo_defludp);
                                lo->ldo_defludp = ludlist;
                        }
-                       return rc;
+                       break;
                }
 
        case LDAP_OPT_DEFBASE: {
@@ -587,24 +634,32 @@ ldap_set_option(
 
                        if ( newbase != NULL ) {
                                defbase = LDAP_STRDUP( newbase );
-                               if ( defbase == NULL ) return LDAP_NO_MEMORY;
+                               if ( defbase == NULL ) {
+                                       rc = LDAP_NO_MEMORY;
+                                       break;
+                               }
 
                        } else if ( ld != NULL ) {
                                defbase = LDAP_STRDUP( ldap_int_global_options.ldo_defbase );
-                               if ( defbase == NULL ) return LDAP_NO_MEMORY;
+                               if ( defbase == NULL ) {
+                                       rc = LDAP_NO_MEMORY;
+                                       break;
+                               }
                        }
                        
                        if ( lo->ldo_defbase != NULL )
                                LDAP_FREE( lo->ldo_defbase );
                        lo->ldo_defbase = defbase;
-               } return LDAP_OPT_SUCCESS;
+               }
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        case LDAP_OPT_DIAGNOSTIC_MESSAGE: {
                        const char *err = (const char *) invalue;
 
                        if(ld == NULL) {
                                /* need a struct ldap */
-                               return LDAP_OPT_ERROR;
+                               break;  /* LDAP_OPT_ERROR */
                        }
 
                        if( ld->ld_error ) {
@@ -615,14 +670,16 @@ ldap_set_option(
                        if ( err ) {
                                ld->ld_error = LDAP_STRDUP(err);
                        }
-               } return LDAP_OPT_SUCCESS;
+               }
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        case LDAP_OPT_MATCHED_DN: {
                        const char *matched = (const char *) invalue;
 
                        if (ld == NULL) {
                                /* need a struct ldap */
-                               return LDAP_OPT_ERROR;
+                               break;  /* LDAP_OPT_ERROR */
                        }
 
                        if( ld->ld_matched ) {
@@ -633,14 +690,16 @@ ldap_set_option(
                        if ( matched ) {
                                ld->ld_matched = LDAP_STRDUP( matched );
                        }
-               } return LDAP_OPT_SUCCESS;
+               }
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        case LDAP_OPT_REFERRAL_URLS: {
                        char *const *referrals = (char *const *) invalue;
                        
                        if(ld == NULL) {
                                /* need a struct ldap */
-                               return LDAP_OPT_ERROR;
+                               break;  /* LDAP_OPT_ERROR */
                        }
 
                        if( ld->ld_referrals ) {
@@ -650,38 +709,52 @@ ldap_set_option(
                        if ( referrals ) {
                                ld->ld_referrals = ldap_value_dup(referrals);
                        }
-               } return LDAP_OPT_SUCCESS;
+               }
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        /* Only accessed from inside this function by ldap_set_rebind_proc() */
        case LDAP_OPT_REBIND_PROC: {
                        lo->ldo_rebind_proc = (LDAP_REBIND_PROC *)invalue;              
-               } return LDAP_OPT_SUCCESS;
+               }
+               rc = LDAP_OPT_SUCCESS;
+               break;
        case LDAP_OPT_REBIND_PARAMS: {
                        lo->ldo_rebind_params = (void *)invalue;                
-               } return LDAP_OPT_SUCCESS;
+               }
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        /* Only accessed from inside this function by ldap_set_nextref_proc() */
        case LDAP_OPT_NEXTREF_PROC: {
                        lo->ldo_nextref_proc = (LDAP_NEXTREF_PROC *)invalue;            
-               } return LDAP_OPT_SUCCESS;
+               }
+               rc = LDAP_OPT_SUCCESS;
+               break;
        case LDAP_OPT_NEXTREF_PARAMS: {
                        lo->ldo_nextref_params = (void *)invalue;               
-               } return LDAP_OPT_SUCCESS;
+               }
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        /* Only accessed from inside this function by ldap_set_urllist_proc() */
        case LDAP_OPT_URLLIST_PROC: {
                        lo->ldo_urllist_proc = (LDAP_URLLIST_PROC *)invalue;            
-               } return LDAP_OPT_SUCCESS;
+               }
+               rc = LDAP_OPT_SUCCESS;
+               break;
        case LDAP_OPT_URLLIST_PARAMS: {
                        lo->ldo_urllist_params = (void *)invalue;               
-               } return LDAP_OPT_SUCCESS;
+               }
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        /* read-only options */
        case LDAP_OPT_API_INFO:
        case LDAP_OPT_DESC:
        case LDAP_OPT_SOCKBUF:
        case LDAP_OPT_API_FEATURE_INFO:
-               return LDAP_OPT_ERROR;
+               break;  /* LDAP_OPT_ERROR */
 
        /* options which cannot withstand invalue == NULL */
        case LDAP_OPT_DEREF:
@@ -698,25 +771,29 @@ ldap_set_option(
        case LDAP_OPT_X_KEEPALIVE_INTERVAL :
                if(invalue == NULL) {
                        /* no place to set from */
-                       return LDAP_OPT_ERROR;
+                       LDAP_MUTEX_UNLOCK( &lo->ldo_mutex );
+                       return ( LDAP_OPT_ERROR );
                }
                break;
 
        default:
 #ifdef HAVE_TLS
                if ( ldap_pvt_tls_set_option( ld, option, (void *)invalue ) == 0 )
-                       return LDAP_OPT_SUCCESS;
+                       LDAP_MUTEX_UNLOCK( &lo->ldo_mutex );
+                       return ( LDAP_OPT_SUCCESS );
 #endif
 #ifdef HAVE_CYRUS_SASL
                if ( ldap_int_sasl_set_option( ld, option, (void *)invalue ) == 0 )
-                       return LDAP_OPT_SUCCESS;
+                       LDAP_MUTEX_UNLOCK( &lo->ldo_mutex );
+                       return ( LDAP_OPT_SUCCESS );
 #endif
 #ifdef HAVE_GSSAPI
                if ( ldap_int_gssapi_set_option( ld, option, (void *)invalue ) == 0 )
-                       return LDAP_OPT_SUCCESS;
+                       LDAP_MUTEX_UNLOCK( &lo->ldo_mutex );
+                       return ( LDAP_OPT_SUCCESS );
 #endif
                /* bad param */
-               return LDAP_OPT_ERROR;
+               break;  /* LDAP_OPT_ERROR */
        }
 
        /* options which cannot withstand invalue == NULL */
@@ -725,31 +802,38 @@ ldap_set_option(
        case LDAP_OPT_DEREF:
                /* FIXME: check value for protocol compliance? */
                lo->ldo_deref = * (const int *) invalue;
-               return LDAP_OPT_SUCCESS;
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        case LDAP_OPT_SIZELIMIT:
                /* FIXME: check value for protocol compliance? */
                lo->ldo_sizelimit = * (const int *) invalue;
-               return LDAP_OPT_SUCCESS;
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        case LDAP_OPT_TIMELIMIT:
                /* FIXME: check value for protocol compliance? */
                lo->ldo_timelimit = * (const int *) invalue;
-               return LDAP_OPT_SUCCESS;
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        case LDAP_OPT_TIMEOUT: {
                        const struct timeval *tv = 
                                (const struct timeval *) invalue;
 
                        lo->ldo_tm_api = *tv;
-               } return LDAP_OPT_SUCCESS;
+               }
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        case LDAP_OPT_NETWORK_TIMEOUT: {
                        const struct timeval *tv = 
                                (const struct timeval *) invalue;
 
                        lo->ldo_tm_net = *tv;
-               } return LDAP_OPT_SUCCESS;
+               }
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        case LDAP_OPT_PROTOCOL_VERSION: {
                        int vers = * (const int *) invalue;
@@ -758,7 +842,9 @@ ldap_set_option(
                                break;
                        }
                        lo->ldo_version = vers;
-               } return LDAP_OPT_SUCCESS;
+               }
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        case LDAP_OPT_RESULT_CODE: {
                        int err = * (const int *) invalue;
@@ -769,11 +855,14 @@ ldap_set_option(
                        }
 
                        ld->ld_errno = err;
-               } return LDAP_OPT_SUCCESS;
+               }
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        case LDAP_OPT_DEBUG_LEVEL:
                lo->ldo_debug = * (const int *) invalue;
-               return LDAP_OPT_SUCCESS;
+               rc = LDAP_OPT_SUCCESS;
+               break;
 
        case LDAP_OPT_CONNECT_CB:
                {
@@ -784,19 +873,24 @@ ldap_set_option(
                        ll->ll_next = lo->ldo_conn_cbs;
                        lo->ldo_conn_cbs = ll;
                }
-               return LDAP_OPT_SUCCESS;
+               rc = LDAP_OPT_SUCCESS;
+               break;
        case LDAP_OPT_X_KEEPALIVE_IDLE:
                lo->ldo_keepalive_idle = * (const int *) invalue;
-               return LDAP_OPT_SUCCESS;
+               rc = LDAP_OPT_SUCCESS;
+               break;
        case LDAP_OPT_X_KEEPALIVE_PROBES :
                lo->ldo_keepalive_probes = * (const int *) invalue;
-               return LDAP_OPT_SUCCESS;
+               rc = LDAP_OPT_SUCCESS;
+               break;
        case LDAP_OPT_X_KEEPALIVE_INTERVAL :
                lo->ldo_keepalive_interval = * (const int *) invalue;
-               return LDAP_OPT_SUCCESS;
+               rc = LDAP_OPT_SUCCESS;
+               break;
        
        }
-       return LDAP_OPT_ERROR;
+       LDAP_MUTEX_UNLOCK( &lo->ldo_mutex );
+       return ( rc );
 }
 
 int
index 9a59c663f9089e7afab1d32f840bc95731440a06..38b4466ba69f63a76bf969c2ebc93f02b807d451 100644 (file)
 #include "ldap-int.h"
 #include "lber.h"
 
+/* used by ldap_send_server_request and ldap_new_connection */
+#ifdef LDAP_R_COMPILE
+#define LDAP_CONN_LOCK_IF(nolock) \
+       { if (nolock) LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); }
+#define LDAP_CONN_UNLOCK_IF(nolock) \
+       { if (nolock) LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); }
+#define LDAP_REQ_LOCK_IF(nolock) \
+       { if (nolock) LDAP_MUTEX_LOCK( &ld->ld_req_mutex ); }
+#define LDAP_REQ_UNLOCK_IF(nolock) \
+       { if (nolock) LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); }
+#define LDAP_RES_LOCK_IF(nolock) \
+       { if (nolock) LDAP_MUTEX_LOCK( &ld->ld_res_mutex ); }
+#define LDAP_RES_UNLOCK_IF(nolock) \
+       { if (nolock) LDAP_MUTEX_UNLOCK( &ld->ld_res_mutex ); }
+#else
+#define LDAP_CONN_LOCK_IF(nolock)
+#define LDAP_CONN_UNLOCK_IF(nolock)
+#define LDAP_REQ_LOCK_IF(nolock)
+#define LDAP_REQ_UNLOCK_IF(nolock)
+#define LDAP_RES_LOCK_IF(nolock)
+#define LDAP_RES_UNLOCK_IF(nolock)
+#endif
+
 static LDAPConn *find_connection LDAP_P(( LDAP *ld, LDAPURLDesc *srv, int any ));
 static void use_connection LDAP_P(( LDAP *ld, LDAPConn *lc ));
 static void ldap_free_request_int LDAP_P(( LDAP *ld, LDAPRequest *lr ));
@@ -82,10 +105,12 @@ ldap_alloc_ber_with_options( LDAP *ld )
 void
 ldap_set_ber_options( LDAP *ld, BerElement *ber )
 {
+       /* ld_lberoptions is constant, hence no lock */
        ber->ber_options = ld->ld_lberoptions;
 }
 
 
+/* sets needed mutexes - no mutexes set to this point */
 ber_int_t
 ldap_send_initial_request(
        LDAP *ld,
@@ -98,15 +123,15 @@ ldap_send_initial_request(
 
        Debug( LDAP_DEBUG_TRACE, "ldap_send_initial_request\n", 0, 0, 0 );
 
-       LDAP_MUTEX_LOCK( &ld->ld_req_mutex );
+       LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
        if ( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, NULL ) == -1 ) {
                /* not connected yet */
                rc = ldap_open_defconn( ld );
 
        }
-       LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
        if( rc < 0 ) {
                ber_free( ber, 1 );
+               LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
                return( -1 );
        } else if ( rc == 0 ) {
                Debug( LDAP_DEBUG_TRACE,
@@ -117,27 +142,33 @@ ldap_send_initial_request(
 #ifdef LDAP_CONNECTIONLESS
        if (LDAP_IS_UDP(ld)) {
                if (msgtype == LDAP_REQ_BIND) {
+                       LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex );
                        if (ld->ld_options.ldo_cldapdn)
                                ldap_memfree(ld->ld_options.ldo_cldapdn);
                        ld->ld_options.ldo_cldapdn = ldap_strdup(dn);
                        ber_free( ber, 1 );
+                       LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex );
+                       LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
                        return 0;
                }
                if (msgtype != LDAP_REQ_ABANDON && msgtype != LDAP_REQ_SEARCH)
                {
                        ber_free( ber, 1 );
+                       LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
                        return LDAP_PARAM_ERROR;
                }
        }
 #endif
        LDAP_MUTEX_LOCK( &ld->ld_req_mutex );
        rc = ldap_send_server_request( ld, ber, msgid, NULL,
-               NULL, NULL, NULL );
+               NULL, NULL, NULL, 0, 0 );
        LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
+       LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
        return(rc);
 }
 
 
+/* protected by conn_mutex */
 int
 ldap_int_flush_request(
        LDAP *ld,
@@ -145,6 +176,7 @@ ldap_int_flush_request(
 {
        LDAPConn *lc = lr->lr_conn;
 
+       LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex );
        if ( ber_flush2( lc->lconn_sb, lr->lr_ber, LBER_FLUSH_FREE_NEVER ) != 0 ) {
                if ( sock_errno() == EAGAIN ) {
                        /* need to continue write later */
@@ -171,6 +203,13 @@ ldap_int_flush_request(
        return 0;
 }
 
+/*
+ * protected by req_mutex
+ * if m_noconn then protect using conn_lock
+ * else already protected with conn_lock
+ * if m_res then also protected by res_mutex
+ */
+
 int
 ldap_send_server_request(
        LDAP *ld,
@@ -179,16 +218,20 @@ ldap_send_server_request(
        LDAPRequest *parentreq,
        LDAPURLDesc **srvlist,
        LDAPConn *lc,
-       LDAPreqinfo *bind )
+       LDAPreqinfo *bind,
+       int m_noconn,
+       int m_res )
 {
        LDAPRequest     *lr;
        int             incparent, rc;
 
+       LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex );
        Debug( LDAP_DEBUG_TRACE, "ldap_send_server_request\n", 0, 0, 0 );
 
        incparent = 0;
        ld->ld_errno = LDAP_SUCCESS;    /* optimistic */
 
+       LDAP_CONN_LOCK_IF(m_noconn);
        if ( lc == NULL ) {
                if ( srvlist == NULL ) {
                        lc = ld->ld_defconn;
@@ -200,7 +243,8 @@ ldap_send_server_request(
                                        incparent = 1;
                                        ++parentreq->lr_outrefcnt;
                                }
-                               lc = ldap_new_connection( ld, srvlist, 0, 1, bind );
+                               lc = ldap_new_connection( ld, srvlist, 0,
+                                       1, bind, 1, m_res );
                        }
                }
        }
@@ -223,11 +267,13 @@ ldap_send_server_request(
                        /* async only occurs if a network timeout is set */
 
                        /* honor network timeout */
+                       LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex );
                        if ( time( NULL ) - lc->lconn_created <= ld->ld_options.ldo_tm_net.tv_sec )
                        {
                                /* caller will have to call again */
                                ld->ld_errno = LDAP_X_CONNECTING;
                        }
+                       LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex );
                        /* fallthru */
 
                default:
@@ -246,6 +292,7 @@ ldap_send_server_request(
                        /* Forget about the bind */
                        --parentreq->lr_outrefcnt; 
                }
+               LDAP_CONN_UNLOCK_IF(m_noconn);
                return( -1 );
        }
 
@@ -255,10 +302,13 @@ ldap_send_server_request(
        if ( LDAP_IS_UDP( ld )) {
                BerElement tmpber = *ber;
                ber_rewind( &tmpber );
+               LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex );
                rc = ber_write( &tmpber, ld->ld_options.ldo_peer,
                        sizeof( struct sockaddr ), 0 );
+               LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex );
                if ( rc == -1 ) {
                        ld->ld_errno = LDAP_ENCODING_ERROR;
+                       LDAP_CONN_UNLOCK_IF(m_noconn);
                        return rc;
                }
        }
@@ -276,7 +326,10 @@ ldap_send_server_request(
        {
                rc = -1;
        }
-       if ( rc ) return rc;
+       if ( rc ) {
+               LDAP_CONN_UNLOCK_IF(m_noconn);
+               return rc;
+       }
 
        lr = (LDAPRequest *)LDAP_CALLOC( 1, sizeof( LDAPRequest ) );
        if ( lr == NULL ) {
@@ -287,6 +340,7 @@ ldap_send_server_request(
                        /* Forget about the bind */
                        --parentreq->lr_outrefcnt; 
                }
+               LDAP_CONN_UNLOCK_IF(m_noconn);
                return( -1 );
        } 
        lr->lr_msgid = msgid;
@@ -345,6 +399,7 @@ ldap_send_server_request(
                msgid = -1;
        }
 
+       LDAP_CONN_UNLOCK_IF(m_noconn);
        return( msgid );
 }
 
@@ -375,18 +430,17 @@ find_tls_ext( LDAPURLDesc *srv )
 }
 
 /*
- * caller must hold ld_req_mutex or be exclusive user of ld
- * if ( connect != 0 ) or ( bind != NULL ) caller must also hold
- * ld_req_mutex and ld_res_mutex
+ * always protected by conn_mutex
+ * optionally protected by req_mutex and res_mutex
  */
-
 LDAPConn *
 ldap_new_connection( LDAP *ld, LDAPURLDesc **srvlist, int use_ldsb,
-       int connect, LDAPreqinfo *bind )
+       int connect, LDAPreqinfo *bind, int m_req, int m_res )
 {
        LDAPConn        *lc;
        int             async = 0;
 
+       LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex );
        Debug( LDAP_DEBUG_TRACE, "ldap_new_connection %d %d %d\n",
                use_ldsb, connect, (bind != NULL) );
        /*
@@ -445,15 +499,10 @@ ldap_new_connection( LDAP *ld, LDAPURLDesc **srvlist, int use_ldsb,
        }
 
        lc->lconn_status = async ? LDAP_CONNST_CONNECTING : LDAP_CONNST_CONNECTED;
-       LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
        lc->lconn_next = ld->ld_conns;
        ld->ld_conns = lc;
-       LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
 
        if ( connect ) {
-               LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex );
-               LDAP_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex );
-
 #ifdef HAVE_TLS
                if ( lc->lconn_server->lud_exts ) {
                        int rc, ext = find_tls_ext( lc->lconn_server );
@@ -464,11 +513,13 @@ ldap_new_connection( LDAP *ld, LDAPURLDesc **srvlist, int use_ldsb,
                                ++lc->lconn_refcnt;     /* avoid premature free */
                                ld->ld_defconn = lc;
 
-                               LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
-                               LDAP_MUTEX_UNLOCK( &ld->ld_res_mutex );
+                               LDAP_REQ_UNLOCK_IF(m_req);
+                               LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
+                               LDAP_RES_UNLOCK_IF(m_res);
                                rc = ldap_start_tls_s( ld, NULL, NULL );
-                               LDAP_MUTEX_LOCK( &ld->ld_res_mutex );
-                               LDAP_MUTEX_LOCK( &ld->ld_req_mutex );
+                               LDAP_RES_LOCK_IF(m_res);
+                               LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
+                               LDAP_REQ_LOCK_IF(m_req);
                                ld->ld_defconn = savedefconn;
                                --lc->lconn_refcnt;
 
@@ -485,9 +536,6 @@ ldap_new_connection( LDAP *ld, LDAPURLDesc **srvlist, int use_ldsb,
                int             err = 0;
                LDAPConn        *savedefconn;
 
-               LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex );
-               LDAP_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex );
-
                /* Set flag to prevent additional referrals
                 * from being processed on this
                 * connection until the bind has completed
@@ -507,13 +555,15 @@ ldap_new_connection( LDAP *ld, LDAPURLDesc **srvlist, int use_ldsb,
                                ld->ld_defconn = lc;
 
                                Debug( LDAP_DEBUG_TRACE, "Call application rebind_proc\n", 0, 0, 0);
-                               LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
-                               LDAP_MUTEX_UNLOCK( &ld->ld_res_mutex );
+                               LDAP_REQ_UNLOCK_IF(m_req);
+                               LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
+                               LDAP_RES_UNLOCK_IF(m_res);
                                err = (*ld->ld_rebind_proc)( ld,
                                        bind->ri_url, bind->ri_request, bind->ri_msgid,
                                        ld->ld_rebind_params );
-                               LDAP_MUTEX_LOCK( &ld->ld_res_mutex );
-                               LDAP_MUTEX_LOCK( &ld->ld_req_mutex );
+                               LDAP_RES_LOCK_IF(m_res);
+                               LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
+                               LDAP_REQ_LOCK_IF(m_req);
 
                                ld->ld_defconn = savedefconn;
                                --lc->lconn_refcnt;
@@ -538,8 +588,9 @@ ldap_new_connection( LDAP *ld, LDAPURLDesc **srvlist, int use_ldsb,
                                "anonymous rebind via ldap_sasl_bind(\"\")\n",
                                0, 0, 0);
 
-                       LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
-                       LDAP_MUTEX_UNLOCK( &ld->ld_res_mutex );
+                       LDAP_REQ_UNLOCK_IF(m_req);
+                       LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
+                       LDAP_RES_UNLOCK_IF(m_res);
                        rc = ldap_sasl_bind( ld, "", LDAP_SASL_SIMPLE, &passwd,
                                NULL, NULL, &msgid );
                        if ( rc != LDAP_SUCCESS ) {
@@ -583,8 +634,9 @@ ldap_new_connection( LDAP *ld, LDAPURLDesc **srvlist, int use_ldsb,
                                        }
                                }
                        }
-                       LDAP_MUTEX_LOCK( &ld->ld_res_mutex );
-                       LDAP_MUTEX_LOCK( &ld->ld_req_mutex );
+                       LDAP_RES_LOCK_IF(m_res);
+                       LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
+                       LDAP_REQ_LOCK_IF(m_req);
                        ld->ld_defconn = savedefconn;
                        --lc->lconn_refcnt;
 
@@ -596,11 +648,11 @@ ldap_new_connection( LDAP *ld, LDAPURLDesc **srvlist, int use_ldsb,
                if ( lc != NULL )
                        lc->lconn_rebind_inprogress = 0;
        }
-
        return( lc );
 }
 
 
+/* protected by ld_conn_mutex */
 static LDAPConn *
 find_connection( LDAP *ld, LDAPURLDesc *srv, int any )
 /*
@@ -613,7 +665,7 @@ find_connection( LDAP *ld, LDAPURLDesc *srv, int any )
        int lcu_port, lsu_port;
        int found = 0;
 
-       LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
+       LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex );
        for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {
                lcu = lc->lconn_server;
                lcu_port = ldap_pvt_url_scheme_port( lcu->lud_scheme,
@@ -637,35 +689,34 @@ find_connection( LDAP *ld, LDAPURLDesc *srv, int any )
                if ( found )
                        break;
        }
-       LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
        return lc;
 }
 
 
-/*
- * NOTE: the caller holds ld_req_mutex
- */
 
+/* protected by ld_conn_mutex */
 static void
 use_connection( LDAP *ld, LDAPConn *lc )
 {
+       LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex );
        ++lc->lconn_refcnt;
        lc->lconn_lastused = time( NULL );
 }
 
 
+/* protected by ld_conn_mutex */
 void
 ldap_free_connection( LDAP *ld, LDAPConn *lc, int force, int unbind )
 {
        LDAPConn        *tmplc, *prevlc;
 
+       LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex );
        Debug( LDAP_DEBUG_TRACE,
                "ldap_free_connection %d %d\n",
                force, unbind, 0 );
 
        if ( force || --lc->lconn_refcnt <= 0 ) {
                /* remove from connections list first */
-               LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
 
                for ( prevlc = NULL, tmplc = ld->ld_conns;
                        tmplc != NULL;
@@ -684,7 +735,6 @@ ldap_free_connection( LDAP *ld, LDAPConn *lc, int force, int unbind )
                        }
                        prevlc = tmplc;
                }
-               LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
 
                /* process connection callbacks */
                {
@@ -693,19 +743,23 @@ ldap_free_connection( LDAP *ld, LDAPConn *lc, int force, int unbind )
                        ldap_conncb *cb;
 
                        lo = &ld->ld_options;
+                       LDAP_MUTEX_LOCK( &lo->ldo_mutex );
                        if ( lo->ldo_conn_cbs ) {
                                for ( ll=lo->ldo_conn_cbs; ll; ll=ll->ll_next ) {
                                        cb = ll->ll_data;
                                        cb->lc_del( ld, lc->lconn_sb, cb );
                                }
                        }
+                       LDAP_MUTEX_UNLOCK( &lo->ldo_mutex );
                        lo = LDAP_INT_GLOBAL_OPT();
+                       LDAP_MUTEX_LOCK( &lo->ldo_mutex );
                        if ( lo->ldo_conn_cbs ) {
                                for ( ll=lo->ldo_conn_cbs; ll; ll=ll->ll_next ) {
                                        cb = ll->ll_data;
                                        cb->lc_del( ld, lc->lconn_sb, cb );
                                }
                        }
+                       LDAP_MUTEX_UNLOCK( &lo->ldo_mutex );
                }
 
                if ( lc->lconn_status == LDAP_CONNST_CONNECTED ) {
@@ -773,6 +827,7 @@ ldap_free_connection( LDAP *ld, LDAPConn *lc, int force, int unbind )
 }
 
 
+/* Protects self with ld_conn_mutex */
 #ifdef LDAP_DEBUG
 void
 ldap_dump_connection( LDAP *ld, LDAPConn *lconns, int all )
@@ -781,6 +836,7 @@ ldap_dump_connection( LDAP *ld, LDAPConn *lconns, int all )
        char            timebuf[32];
 
        Debug( LDAP_DEBUG_TRACE, "** ld %p Connection%s:\n", (void *)ld, all ? "s" : "", 0 );
+       LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
        for ( lc = lconns; lc != NULL; lc = lc->lconn_next ) {
                if ( lc->lconn_server != NULL ) {
                        Debug( LDAP_DEBUG_TRACE, "* host: %s  port: %d%s\n",
@@ -817,9 +873,11 @@ ldap_dump_connection( LDAP *ld, LDAPConn *lconns, int all )
                        break;
                }
        }
+       LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
 }
 
 
+/* protected by req_mutex and res_mutex */
 void
 ldap_dump_requests_and_responses( LDAP *ld )
 {
@@ -868,9 +926,11 @@ ldap_dump_requests_and_responses( LDAP *ld )
 }
 #endif /* LDAP_DEBUG */
 
+/* protected by req_mutex */
 static void
 ldap_free_request_int( LDAP *ld, LDAPRequest *lr )
 {
+       LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex );
        /* if lr_refcnt > 0, the request has been looked up 
         * by ldap_find_request_by_msgid(); if in the meanwhile
         * the request is free()'d by someone else, just decrease
@@ -921,11 +981,11 @@ ldap_free_request_int( LDAP *ld, LDAPRequest *lr )
        LDAP_FREE( lr );
 }
 
+/* protected by req_mutex */
 void
 ldap_free_request( LDAP *ld, LDAPRequest *lr )
 {
        LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex );
-
        Debug( LDAP_DEBUG_TRACE, "ldap_free_request (origid %d, msgid %d)\n",
                lr->lr_origid, lr->lr_msgid, 0 );
 
@@ -993,6 +1053,8 @@ static int ldap_int_nextref(
  *  (OUT) hadrefp = 1 if sucessfully followed referral
  *
  * Return value - number of referrals followed
+ *
+ * Protected by res_mutex, conn_mutex and req_mutex    (try_read1msg)
  */
 int
 ldap_chase_v3referrals( LDAP *ld, LDAPRequest *lr, char **refs, int sref, char **errstrp, int *hadrefp )
@@ -1008,11 +1070,14 @@ ldap_chase_v3referrals( LDAP *ld, LDAPRequest *lr, char **refs, int sref, char *
        LDAPreqinfo  rinfo;
        LDAP_NEXTREF_PROC       *nextref_proc = ld->ld_nextref_proc ? ld->ld_nextref_proc : ldap_int_nextref;
 
+       LDAP_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex );
+       LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex );
+       LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex );
+       Debug( LDAP_DEBUG_TRACE, "ldap_chase_v3referrals\n", 0, 0, 0 );
+
        ld->ld_errno = LDAP_SUCCESS;    /* optimistic */
        *hadrefp = 0;
 
-       Debug( LDAP_DEBUG_TRACE, "ldap_chase_v3referrals\n", 0, 0, 0 );
-
        unfollowed = NULL;
        rc = count = 0;
 
@@ -1184,10 +1249,8 @@ ldap_chase_v3referrals( LDAP *ld, LDAPRequest *lr, char **refs, int sref, char *
                /* Send the new request to the server - may require a bind */
                rinfo.ri_msgid = origreq->lr_origid;
                rinfo.ri_url = refarray[i];
-               LDAP_MUTEX_LOCK( &ld->ld_req_mutex );
                rc = ldap_send_server_request( ld, ber, id,
-                       origreq, &srv, NULL, &rinfo );
-               LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
+                       origreq, &srv, NULL, &rinfo, 0, 1 );
                if ( rc < 0 ) {
                        /* Failure, try next referral in the list */
                        Debug( LDAP_DEBUG_ANY, "Unable to chase referral \"%s\" (%d: %s)\n", 
@@ -1208,6 +1271,7 @@ ldap_chase_v3referrals( LDAP *ld, LDAPRequest *lr, char **refs, int sref, char *
                                if ( lc == NULL ) {
                                        ld->ld_errno = LDAP_OPERATIONS_ERROR;
                                        rc = -1;
+                                       LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
                                        goto done;
                                }
                        }
@@ -1253,6 +1317,7 @@ done:
 
 /*
  * XXX merging of errors in this routine needs to be improved
+ * Protected by res_mutex, conn_mutex and req_mutex    (try_read1msg)
  */
 int
 ldap_chase_referrals( LDAP *ld,
@@ -1270,6 +1335,9 @@ ldap_chase_referrals( LDAP *ld,
        LDAPreqinfo  rinfo;
        LDAPConn        *lc;
 
+       LDAP_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex );
+       LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex );
+       LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex );
        Debug( LDAP_DEBUG_TRACE, "ldap_chase_referrals\n", 0, 0, 0 );
 
        ld->ld_errno = LDAP_SUCCESS;    /* optimistic */
@@ -1367,11 +1435,8 @@ ldap_chase_referrals( LDAP *ld,
 
                rinfo.ri_msgid = origreq->lr_origid;
 
-               LDAP_MUTEX_LOCK( &ld->ld_req_mutex );
                rc = ldap_send_server_request( ld, ber, id,
-                       lr, &srv, NULL, &rinfo );
-               LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
-
+                       lr, &srv, NULL, &rinfo, 0, 1 );
                LDAP_FREE( rinfo.ri_url );
 
                if( rc >= 0 ) {
@@ -1561,12 +1626,12 @@ re_encode_request( LDAP *ld,
 }
 
 
+/* protected by req_mutex */
 LDAPRequest *
 ldap_find_request_by_msgid( LDAP *ld, ber_int_t msgid )
 {
        LDAPRequest     *lr;
 
-       LDAP_MUTEX_LOCK( &ld->ld_req_mutex );
        for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) {
                if ( lr->lr_status == LDAP_REQST_COMPLETED ) {
                        continue;       /* Skip completed requests */
@@ -1576,17 +1641,16 @@ ldap_find_request_by_msgid( LDAP *ld, ber_int_t msgid )
                        break;
                }
        }
-       LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
 
        return( lr );
 }
 
+/* protected by req_mutex */
 void
 ldap_return_request( LDAP *ld, LDAPRequest *lrx, int freeit )
 {
        LDAPRequest     *lr;
 
-       LDAP_MUTEX_LOCK( &ld->ld_req_mutex );
        for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) {
                if ( lr == lrx ) {
                        if ( lr->lr_refcnt > 0 ) {
@@ -1607,5 +1671,4 @@ ldap_return_request( LDAP *ld, LDAPRequest *lrx, int freeit )
        } else if ( freeit ) {
                ldap_free_request( ld, lrx );
        }
-       LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
 }
index 98294d4b8c01f29d1f787f5664052c4362b840c8..15e664aa220df3d07349d3836692a010768d793a 100644 (file)
@@ -66,8 +66,8 @@
 #include "ldap_log.h"
 #include "lutil.h"
 
-static int ldap_abandoned LDAP_P(( LDAP *ld, ber_int_t msgid, int *idx ));
-static int ldap_mark_abandoned LDAP_P(( LDAP *ld, ber_int_t msgid, int idx ));
+static int ldap_abandoned LDAP_P(( LDAP *ld, ber_int_t msgid ));
+static int ldap_mark_abandoned LDAP_P(( LDAP *ld, ber_int_t msgid ));
 static int wait4msg LDAP_P(( LDAP *ld, ber_int_t msgid, int all, struct timeval *timeout,
        LDAPMessage **result ));
 static ber_tag_t try_read1msg LDAP_P(( LDAP *ld, ber_int_t msgid,
@@ -120,6 +120,7 @@ ldap_result(
        return rc;
 }
 
+/* protected by res_mutex */
 static LDAPMessage *
 chkResponseList(
        LDAP *ld,
@@ -144,12 +145,10 @@ chkResponseList(
 
        lastlm = &ld->ld_responses;
        for ( lm = ld->ld_responses; lm != NULL; lm = nextlm ) {
-               int     idx;
-
                nextlm = lm->lm_next;
                ++cnt;
 
-               if ( ldap_abandoned( ld, lm->lm_msgid, &idx ) ) {
+               if ( ldap_abandoned( ld, lm->lm_msgid ) ) {
                        Debug( LDAP_DEBUG_ANY,
                                "response list msg abandoned, "
                                "msgid %d message type %s\n",
@@ -164,7 +163,7 @@ chkResponseList(
                        default:
                                /* there's no need to keep the id
                                 * in the abandoned list any longer */
-                               ldap_mark_abandoned( ld, lm->lm_msgid, idx );
+                               ldap_mark_abandoned( ld, lm->lm_msgid );
                                break;
                        }
 
@@ -231,6 +230,7 @@ chkResponseList(
        return lm;
 }
 
+/* protected by res_mutex */
 static int
 wait4msg(
        LDAP *ld,
@@ -284,9 +284,7 @@ wait4msg(
                if ( ldap_debug & LDAP_DEBUG_TRACE ) {
                        Debug( LDAP_DEBUG_TRACE, "wait4msg continue ld %p msgid %d all %d\n",
                                (void *)ld, msgid, all );
-                       LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
                        ldap_dump_connection( ld, ld->ld_conns, 1 );
-                       LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
                        LDAP_MUTEX_LOCK( &ld->ld_req_mutex );
                        ldap_dump_requests_and_responses( ld );
                        LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
@@ -308,7 +306,6 @@ wait4msg(
                                        break;
                                }
                        }
-                       LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
 
                        if ( !lc_ready ) {
                                int err;
@@ -328,6 +325,7 @@ wait4msg(
                                {
                                        ld->ld_errno = (rc == -1 ? LDAP_SERVER_DOWN :
                                                LDAP_TIMEOUT);
+                                       LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
                                        return( rc );
                                }
 
@@ -349,8 +347,6 @@ wait4msg(
                                {
                                        ldap_int_flush_request( ld, ld->ld_requests );
                                }
-                               LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
-                               LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
                                for ( lc = ld->ld_conns;
                                        rc == LDAP_MSG_X_KEEP_LOOKING && lc != NULL;
                                        lc = lnext )
@@ -360,25 +356,22 @@ wait4msg(
                                        {
                                                /* Don't let it get freed out from under us */
                                                ++lc->lconn_refcnt;
-                                               LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
                                                rc = try_read1msg( ld, msgid, all, lc, result );
                                                lnext = lc->lconn_next;
 
                                                /* Only take locks if we're really freeing */
                                                if ( lc->lconn_refcnt <= 1 ) {
-                                                       LDAP_MUTEX_LOCK( &ld->ld_req_mutex );
                                                        ldap_free_connection( ld, lc, 0, 1 );
-                                                       LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
                                                } else {
                                                        --lc->lconn_refcnt;
                                                }
-                                               LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
                                        } else {
                                                lnext = lc->lconn_next;
                                        }
                                }
-                               LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
+                               LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
                        }
+                       LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
                }
 
                if ( rc == LDAP_MSG_X_KEEP_LOOKING && tvp != NULL ) {
@@ -432,6 +425,7 @@ wait4msg(
 }
 
 
+/* protected by res_mutex, conn_mutex and req_mutex */
 static ber_tag_t
 try_read1msg(
        LDAP *ld,
@@ -443,7 +437,6 @@ try_read1msg(
        BerElement      *ber;
        LDAPMessage     *newmsg, *l, *prev;
        ber_int_t       id;
-       int             idx;
        ber_tag_t       tag;
        ber_len_t       len;
        int             foundit = 0;
@@ -461,6 +454,8 @@ try_read1msg(
        assert( lc != NULL );
        
        LDAP_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex );
+       LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex );
+       LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex );
 
        Debug( LDAP_DEBUG_TRACE, "read1msg: ld %p msgid %d all %d\n",
                (void *)ld, msgid, all );
@@ -531,7 +526,7 @@ nextresp3:
        
        /* if it's been abandoned, toss it */
        if ( id > 0 ) {
-               if ( ldap_abandoned( ld, id, &idx ) ) {
+               if ( ldap_abandoned( ld, id ) ) {
                        /* the message type */
                        tag = ber_peek_tag( ber, &len );
                        switch ( tag ) {
@@ -544,7 +539,7 @@ nextresp3:
                        default:
                                /* there's no need to keep the id
                                 * in the abandoned list any longer */
-                               ldap_mark_abandoned( ld, id, idx );
+                               ldap_mark_abandoned( ld, id );
                                break;
                        }
 
@@ -1340,35 +1335,37 @@ ldap_msgdelete( LDAP *ld, int msgid )
  *
  * return the location of the message id in the array of abandoned
  * message ids, or -1
- *
- * expects ld_res_mutex to be locked
  */
 static int
-ldap_abandoned( LDAP *ld, ber_int_t msgid, int *idxp )
+ldap_abandoned( LDAP *ld, ber_int_t msgid )
 {
-       LDAP_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex );
-
-       assert( idxp != NULL );
+       int     ret, idx;
        assert( msgid >= 0 );
 
-       return ldap_int_bisect_find( ld->ld_abandoned, ld->ld_nabandoned, msgid, idxp );
+       LDAP_MUTEX_LOCK( &ld->ld_abandon_mutex );
+       ret = ldap_int_bisect_find( ld->ld_abandoned, ld->ld_nabandoned, msgid, &idx );
+       LDAP_MUTEX_UNLOCK( &ld->ld_abandon_mutex );
+       return ret;
 }
 
 /*
  * ldap_mark_abandoned
- *
- * expects ld_res_mutex to be locked
  */
 static int
-ldap_mark_abandoned( LDAP *ld, ber_int_t msgid, int idx )
+ldap_mark_abandoned( LDAP *ld, ber_int_t msgid )
 {
-       LDAP_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex );
+       int     ret, idx;
 
-       /* NOTE: those assertions are repeated in ldap_int_bisect_delete() */
-       assert( idx >= 0 );
-       assert( (unsigned) idx < ld->ld_nabandoned );
-       assert( ld->ld_abandoned[ idx ] == msgid );
-
-       return ldap_int_bisect_delete( &ld->ld_abandoned, &ld->ld_nabandoned,
+       assert( msgid >= 0 );
+       LDAP_MUTEX_LOCK( &ld->ld_abandon_mutex );
+       ret = ldap_int_bisect_find( ld->ld_abandoned, ld->ld_nabandoned, msgid, &idx );
+       if (ret <= 0) {         /* error or already deleted by another thread */
+               LDAP_MUTEX_UNLOCK( &ld->ld_abandon_mutex );
+               return ret;
+       }
+       /* still in abandoned array, so delete */
+       ret = ldap_int_bisect_delete( &ld->ld_abandoned, &ld->ld_nabandoned,
                msgid, idx );
+       LDAP_MUTEX_UNLOCK( &ld->ld_abandon_mutex );
+       return ret;
 }
index ce0cff1fb13d68d88313f5e815e328859e726e81..58ccf970ceb866d161e4927eae68aa3d357435f4 100644 (file)
 
 #include "ldap-tls.h"
 
-#ifdef LDAP_R_COMPILE
-#include <ldap_pvt_thread.h>
-#endif
-
 static tls_impl *tls_imp = &ldap_int_tls_impl;
 #define HAS_TLS( sb )  ber_sockbuf_ctrl( sb, LBER_SB_OPT_HAS_IO, \
                                (void *)tls_imp->ti_sbio )
@@ -269,13 +265,9 @@ ldap_pvt_tls_init_def_ctx( int is_server )
 {
        struct ldapoptions *lo = LDAP_INT_GLOBAL_OPT();   
        int rc;
-#ifdef LDAP_R_COMPILE
-       ldap_pvt_thread_mutex_lock( &tls_def_ctx_mutex );
-#endif
+       LDAP_MUTEX_LOCK( &tls_def_ctx_mutex );
        rc = ldap_int_tls_init_ctx( lo, is_server );
-#ifdef LDAP_R_COMPILE
-       ldap_pvt_thread_mutex_unlock( &tls_def_ctx_mutex );
-#endif
+       LDAP_MUTEX_UNLOCK( &tls_def_ctx_mutex );
        return rc;
 }
 
index 2118d1d4de693469412f46dc6a46e250fc5ff113..5a5cf658ed1ffdf5e7b13cdb0346f7b7297cf05f 100644 (file)
 #include "ldap-int.h"
 #include "ldap-tls.h"
 
-#ifdef LDAP_R_COMPILE
-#include <ldap_pvt_thread.h>
-#endif
-
 #include <gnutls/gnutls.h>
 #include <gnutls/x509.h>
 #include <gcrypt.h>
@@ -257,13 +253,9 @@ static void
 tlsg_ctx_ref( tls_ctx *ctx )
 {
        tlsg_ctx *c = (tlsg_ctx *)ctx;
-#ifdef LDAP_R_COMPILE
-       ldap_pvt_thread_mutex_lock( &c->ref_mutex );
-#endif
+       LDAP_MUTEX_LOCK( &c->ref_mutex );
        c->refcount++;
-#ifdef LDAP_R_COMPILE
-       ldap_pvt_thread_mutex_unlock( &c->ref_mutex );
-#endif
+       LDAP_MUTEX_UNLOCK( &c->ref_mutex );
 }
 
 static void
@@ -274,13 +266,9 @@ tlsg_ctx_free ( tls_ctx *ctx )
 
        if ( !c ) return;
 
-#ifdef LDAP_R_COMPILE
-       ldap_pvt_thread_mutex_lock( &c->ref_mutex );
-#endif
+       LDAP_MUTEX_LOCK( &c->ref_mutex );
        refcount = --c->refcount;
-#ifdef LDAP_R_COMPILE
-       ldap_pvt_thread_mutex_unlock( &c->ref_mutex );
-#endif
+       LDAP_MUTEX_UNLOCK( &c->ref_mutex );
        if ( refcount )
                return;
 #ifdef HAVE_CIPHERSUITES
index c36a5ffa1c34a110dc6489d8df19a4236aedbe47..d921f6a7a161558ae9528e817920c48446dbb1f2 100644 (file)
 #include "ldap-int.h"
 #include "ldap-tls.h"
 
-#ifdef LDAP_R_COMPILE
-#include <ldap_pvt_thread.h>
-#endif
-
 #define READ_PASSWORD_FROM_STDIN
 #define READ_PASSWORD_FROM_FILE
 
@@ -1862,13 +1858,9 @@ static void
 tlsm_ctx_ref( tls_ctx *ctx )
 {
        tlsm_ctx *c = (tlsm_ctx *)ctx;
-#ifdef LDAP_R_COMPILE
-       ldap_pvt_thread_mutex_lock( &c->tc_refmutex );
-#endif
+       LDAP_MUTEX_LOCK( &c->tc_refmutex );
        c->tc_refcnt++;
-#ifdef LDAP_R_COMPILE
-       ldap_pvt_thread_mutex_unlock( &c->tc_refmutex );
-#endif
+       LDAP_MUTEX_UNLOCK( &c->tc_refmutex );
 }
 
 static void
@@ -1879,13 +1871,9 @@ tlsm_ctx_free ( tls_ctx *ctx )
 
        if ( !c ) return;
 
-#ifdef LDAP_R_COMPILE
-       ldap_pvt_thread_mutex_lock( &c->tc_refmutex );
-#endif
+       LDAP_MUTEX_LOCK( &c->tc_refmutex );
        refcount = --c->tc_refcnt;
-#ifdef LDAP_R_COMPILE
-       ldap_pvt_thread_mutex_unlock( &c->tc_refmutex );
-#endif
+       LDAP_MUTEX_UNLOCK( &c->tc_refmutex );
        if ( refcount )
                return;
        if ( c->tc_model )
index 733d18e3656434203eaeb7d5f41300db84c3273e..8a3876779da711e7cef0e9dd8c5b9fa8fba1c4df 100644 (file)
 #include "ldap-int.h"
 #include "ldap-tls.h"
 
-#ifdef LDAP_R_COMPILE
-#include <ldap_pvt_thread.h>
-#endif
-
 #ifdef HAVE_OPENSSL_SSL_H
 #include <openssl/ssl.h>
 #include <openssl/x509v3.h>
@@ -1214,14 +1210,10 @@ tlso_tmp_dh_cb( SSL *ssl, int is_export, int key_length )
        int i;
 
        /* Do we have params of this length already? */
-#ifdef LDAP_R_COMPILE
-       ldap_pvt_thread_mutex_lock( &tlso_dh_mutex );
-#endif
+       LDAP_MUTEX_LOCK( &tlso_dh_mutex );
        for ( p = tlso_dhparams; p; p=p->next ) {
                if ( p->keylength == key_length ) {
-#ifdef LDAP_R_COMPILE
-                       ldap_pvt_thread_mutex_unlock( &tlso_dh_mutex );
-#endif
+                       LDAP_MUTEX_UNLOCK( &tlso_dh_mutex );
                        return p->param;
                }
        }
@@ -1254,9 +1246,7 @@ tlso_tmp_dh_cb( SSL *ssl, int is_export, int key_length )
                }
        }
 
-#ifdef LDAP_R_COMPILE
-       ldap_pvt_thread_mutex_unlock( &tlso_dh_mutex );
-#endif
+       LDAP_MUTEX_UNLOCK( &tlso_dh_mutex );
        return dh;
 }
 
index b76e127f3992805194d7673c942cecc70fa155df..d6f247d9004a15cde8637be0cfeb73ce3ae96988 100644 (file)
@@ -80,18 +80,44 @@ ldap_ld_free(
        LDAPMessage     *lm, *next;
        int             err = LDAP_SUCCESS;
 
+       LDAP_MUTEX_LOCK( &ld->ld_ldcmutex );
+       /* Someone else is still using this ld. */
+       if (ld->ld_ldcrefcnt > 1) {     /* but not last thread */
+               /* clean up self only */
+               ld->ld_ldcrefcnt--;
+               if ( ld->ld_error != NULL ) {
+                       LDAP_FREE( ld->ld_error );
+                       ld->ld_error = NULL;
+               }
+
+               if ( ld->ld_matched != NULL ) {
+                       LDAP_FREE( ld->ld_matched );
+                       ld->ld_matched = NULL;
+               }
+               if ( ld->ld_referrals != NULL) {
+                       LDAP_VFREE(ld->ld_referrals);
+                       ld->ld_referrals = NULL;
+               }  
+               LDAP_MUTEX_UNLOCK( &ld->ld_ldcmutex );
+               LDAP_FREE( (char *) ld );
+               return( err );
+       }
+
+       /* This ld is the last thread. */
+
        /* free LDAP structure and outstanding requests/responses */
        LDAP_MUTEX_LOCK( &ld->ld_req_mutex );
        while ( ld->ld_requests != NULL ) {
                ldap_free_request( ld, ld->ld_requests );
        }
+       LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
+       LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
 
        /* free and unbind from all open connections */
        while ( ld->ld_conns != NULL ) {
                ldap_free_connection( ld, ld->ld_conns, 1, close );
        }
-       LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
-
+       LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
        LDAP_MUTEX_LOCK( &ld->ld_res_mutex );
        for ( lm = ld->ld_responses; lm != NULL; lm = next ) {
                next = lm->lm_next;
@@ -103,6 +129,7 @@ ldap_ld_free(
                ld->ld_abandoned = NULL;
        }
        LDAP_MUTEX_UNLOCK( &ld->ld_res_mutex );
+       LDAP_MUTEX_LOCK( &ld->ld_ldopts_mutex );
 
        /* final close callbacks */
        {
@@ -126,7 +153,7 @@ ldap_ld_free(
                ld->ld_matched = NULL;
        }
 
-       if( ld->ld_referrals != NULL) {
+       if ( ld->ld_referrals != NULL) {
                LDAP_VFREE(ld->ld_referrals);
                ld->ld_referrals = NULL;
        }  
@@ -188,22 +215,35 @@ ldap_ld_free(
                ldap_controls_free( ld->ld_options.ldo_cctrls );
                ld->ld_options.ldo_cctrls = NULL;
        }
+       LDAP_MUTEX_UNLOCK( &ld->ld_ldopts_mutex );
 
        ber_sockbuf_free( ld->ld_sb );   
    
 #ifdef LDAP_R_COMPILE
+       ldap_pvt_thread_mutex_destroy( &ld->ld_msgid_mutex );
+       ldap_pvt_thread_mutex_destroy( &ld->ld_conn_mutex );
        ldap_pvt_thread_mutex_destroy( &ld->ld_req_mutex );
        ldap_pvt_thread_mutex_destroy( &ld->ld_res_mutex );
-       ldap_pvt_thread_mutex_destroy( &ld->ld_conn_mutex );
+       ldap_pvt_thread_mutex_destroy( &ld->ld_abandon_mutex );
+       ldap_pvt_thread_mutex_destroy( &ld->ld_ldopts_mutex );
+       ldap_pvt_thread_mutex_unlock( &ld->ld_ldcmutex );
+       ldap_pvt_thread_mutex_destroy( &ld->ld_ldcmutex );
 #endif
 #ifndef NDEBUG
        LDAP_TRASH(ld);
 #endif
+       LDAP_FREE( (char *) ld->ldc );
        LDAP_FREE( (char *) ld );
    
        return( err );
 }
 
+int
+ldap_destroy( LDAP *ld )
+{
+       return ( ldap_ld_free( ld, 1, NULL, NULL ) );
+}
+
 int
 ldap_unbind_s( LDAP *ld )
 {
@@ -233,7 +273,7 @@ ldap_send_unbind(
                return( ld->ld_errno );
        }
 
-       id = ++(ld)->ld_msgid;
+       LDAP_NEXT_MSGID(ld, id);
 
        /* fill it in */
        if ( ber_printf( ber, "{itn" /*}*/, id,
index 63741758bd668bb886658ed36b0d1d3394e165d5..fe734295c780a8f8036205ea75e5bc639f8c7061 100644 (file)
@@ -32,7 +32,6 @@
 #include <fetch.h>
 #endif
 
-#include "ldap_log.h"
 #include "lber_pvt.h"
 #include "ldap_pvt.h"
 #include "ldap_config.h"
index 6cc9c3f697ea4e79d815dfbb055614e460da5228..87fa0e6c81b161bdc6165bb5638a9ddc1bcf0906 100644 (file)
 
 #include <ldap.h>
 
-#include "ldap_log.h"
 #include "ldap_pvt_thread.h"
 
-
 #include "ldap_defaults.h"
 
 #include "slapdmsg.h"
index 5d8df87e1691d059052b0a99bbb1e70e6e7db89f..702cde2a5d36ca107c2375fb6c01284f703b1005 100644 (file)
@@ -549,7 +549,7 @@ retry:
 
                if ( dnPretty( NULL, &match, &pmatch, op->o_tmpmemctx ) == LDAP_SUCCESS ) {
                        rs->sr_matched = pmatch.bv_val;
-                       LDAP_FREE( match.bv_val );
+                       ber_memfree( match.bv_val );
 
                } else {
                        rs->sr_matched = match.bv_val;
@@ -589,14 +589,14 @@ finish:;
                        ber_memfree_x( (char *)rs->sr_matched, op->o_tmpmemctx );
 
                } else {
-                       LDAP_FREE( match.bv_val );
+                       ber_memfree( match.bv_val );
                }
                rs->sr_matched = save_matched;
        }
 
        if ( rs->sr_text ) {
                if ( freetext ) {
-                       LDAP_FREE( (char *)rs->sr_text );
+                       ber_memfree( (char *)rs->sr_text );
                }
                rs->sr_text = NULL;
        }
@@ -629,7 +629,7 @@ ldap_build_entry(
                struct berval   *bdn )
 {
        struct berval   a;
-       BerElement      ber = *e->lm_ber;
+       BerElement      ber = *ldap_get_message_ber( e );
        Attribute       *attr, **attrp;
        const char      *text;
        int             last;
@@ -764,7 +764,7 @@ ldap_build_entry(
                                        rc = LDAP_SUCCESS;
 
                                } else {
-                                       LBER_FREE( attr->a_vals[i].bv_val );
+                                       ber_memfree( attr->a_vals[i].bv_val );
                                        if ( --last == i ) {
                                                BER_BVZERO( &attr->a_vals[i] );
                                                break;
@@ -776,7 +776,7 @@ ldap_build_entry(
                        }
 
                        if ( rc == LDAP_SUCCESS && pretty ) {
-                               LBER_FREE( attr->a_vals[i].bv_val );
+                               ber_memfree( attr->a_vals[i].bv_val );
                                attr->a_vals[i] = pval;
                        }
                }
@@ -802,7 +802,7 @@ ldap_build_entry(
                                        NULL );
 
                                if ( rc != LDAP_SUCCESS ) {
-                                       LBER_FREE( attr->a_vals[i].bv_val );
+                                       ber_memfree( attr->a_vals[i].bv_val );
                                        if ( --last == i ) {
                                                BER_BVZERO( &attr->a_vals[i] );
                                                break;
@@ -833,8 +833,8 @@ ldap_build_entry(
 
                                /* Strip duplicate values */
                                if ( attr->a_nvals != attr->a_vals )
-                                       LBER_FREE( attr->a_nvals[i].bv_val );
-                               LBER_FREE( attr->a_vals[i].bv_val );
+                                       ber_memfree( attr->a_nvals[i].bv_val );
+                               ber_memfree( attr->a_vals[i].bv_val );
                                attr->a_numvals--;
 
                                assert( i >= 0 );
index 75097574ea17f5d37a7d362f145d4a8ff42cb650..9e42a32225d3da05ae45b2104643ad9949eb21a8 100644 (file)
@@ -711,7 +711,7 @@ ldap_back_referral_result_rewrite(
                         * legal to trim values when adding/modifying;
                         * it should be when searching (e.g. ACLs).
                         */
-                       LBER_FREE( a_vals[ i ].bv_val );
+                       ber_memfree( a_vals[ i ].bv_val );
                        if ( last > i ) {
                                a_vals[ i ] = a_vals[ last ];
                        }
@@ -738,7 +738,7 @@ ldap_back_referral_result_rewrite(
 
                                ber_memfree_x( a_vals[ i ].bv_val, memctx );
                                ber_str2bv_x( newurl, 0, 1, &a_vals[ i ], memctx );
-                               LDAP_FREE( newurl );
+                               ber_memfree( newurl );
                                ludp->lud_dn = olddn.bv_val;
                        }
                        break;
@@ -824,7 +824,7 @@ ldap_dnattr_result_rewrite(
                         * legal to trim values when adding/modifying;
                         * it should be when searching (e.g. ACLs).
                         */
-                       LBER_FREE( a_vals[i].bv_val );
+                       ber_memfree( a_vals[i].bv_val );
                        if ( last > i ) {
                                a_vals[i] = a_vals[last];
                        }
@@ -835,7 +835,7 @@ ldap_dnattr_result_rewrite(
                default:
                        /* leave attr untouched if massage failed */
                        if ( !BER_BVISNULL( &bv ) && a_vals[i].bv_val != bv.bv_val ) {
-                               LBER_FREE( a_vals[i].bv_val );
+                               ber_memfree( a_vals[i].bv_val );
                                a_vals[i] = bv;
                        }
                        break;
index 851cab0c94224fea7fbb5df87b9252d6ea39ea88..41f29346cc6860e30ab4335e7420093ebfc37551 100644 (file)
@@ -2031,7 +2031,7 @@ meta_send_entry(
        int                     check_duplicate_attrs = 0;
        int                     check_sorted_attrs = 0;
        Entry                   ent = { 0 };
-       BerElement              ber = *e->lm_ber;
+       BerElement              ber = *ldap_get_message_ber( e );
        Attribute               *attr, **attrp;
        struct berval           bdn,
                                dn = BER_BVNULL;
@@ -2281,7 +2281,7 @@ remove_oc:;
                                }
 
                                if ( rc ) {
-                                       LBER_FREE( attr->a_vals[i].bv_val );
+                                       ber_memfree( attr->a_vals[i].bv_val );
                                        if ( --last == i ) {
                                                BER_BVZERO( &attr->a_vals[ i ] );
                                                break;
@@ -2293,7 +2293,7 @@ remove_oc:;
                                }
 
                                if ( pretty ) {
-                                       LBER_FREE( attr->a_vals[i].bv_val );
+                                       ber_memfree( attr->a_vals[i].bv_val );
                                        attr->a_vals[i] = pval;
                                }
                        }
@@ -2318,7 +2318,7 @@ remove_oc:;
                                        attr->a_desc->ad_type->sat_equality,
                                        &attr->a_vals[i], &attr->a_nvals[i],
                                        NULL )) {
-                                       LBER_FREE( attr->a_vals[i].bv_val );
+                                       ber_memfree( attr->a_vals[i].bv_val );
                                        if ( --last == i ) {
                                                BER_BVZERO( &attr->a_vals[ i ] );
                                                break;
@@ -2400,8 +2400,8 @@ next_attr:;
 
                                        /* Strip duplicate values */
                                        if ( attr->a_nvals != attr->a_vals )
-                                               LBER_FREE( attr->a_nvals[i].bv_val );
-                                       LBER_FREE( attr->a_vals[i].bv_val );
+                                               ber_memfree( attr->a_nvals[i].bv_val );
+                                       ber_memfree( attr->a_vals[i].bv_val );
                                        attr->a_numvals--;
                                        if ( (unsigned)i < attr->a_numvals ) {
                                                attr->a_vals[i] = attr->a_vals[attr->a_numvals];
index 9e5373653aaffca011e7691995697eec6a1847b5..08b64d3022000ebf03066f21ff8d375c134f3a5b 100644 (file)
@@ -961,7 +961,7 @@ rwm_referral_rewrite(
                                }
 
                                ber_str2bv( newurl, 0, 1, &a_vals[i] );
-                               LDAP_FREE( newurl );
+                               ber_memfree( newurl );
 
                                if ( pa_nvals ) {
                                        ludp->lud_dn = ndn.bv_val;
@@ -981,7 +981,7 @@ rwm_referral_rewrite(
                                                ch_free( (*pa_nvals)[i].bv_val );
                                        }
                                        ber_str2bv( newurl, 0, 1, &(*pa_nvals)[i] );
-                                       LDAP_FREE( newurl );
+                                       ber_memfree( newurl );
                                }
 
                                ch_free( oldval.bv_val );
@@ -1192,7 +1192,7 @@ rwm_referral_result_rewrite(
 
                                ch_free( a_vals[i].bv_val );
                                ber_str2bv( newurl, 0, 1, &a_vals[i] );
-                               LDAP_FREE( newurl );
+                               ber_memfree( newurl );
                                ludp->lud_dn = olddn.bv_val;
                        }
                        break;
index c7477881fc5dfef038ba715720d0b8fe125991df..e31e2c62d6611e723979d00fb034520aa2b46d1c 100644 (file)
 ## <http://www.OpenLDAP.org/license.html>.
 
 PROGRAMS = slapd-tester slapd-search slapd-read slapd-addel slapd-modrdn \
-               slapd-modify slapd-bind ldif-filter
+               slapd-modify slapd-bind slapd-mtread ldif-filter
 
 SRCS     = slapd-common.c \
                slapd-tester.c slapd-search.c slapd-read.c slapd-addel.c \
-               slapd-modrdn.c slapd-modify.c slapd-bind.c ldif-filter.c
+               slapd-modrdn.c slapd-modify.c slapd-bind.c slapd-mtread.c \
+               ldif-filter.c
 
 LDAP_INCDIR= ../../include
 LDAP_LIBDIR= ../../libraries
 
 XLIBS    = $(LDAP_LIBLDAP_LA) $(LDAP_LIBLUTIL_A) $(LDAP_LIBLBER_LA)
+XRLIBS    = $(LDAP_LIBLDAP_R_LA) $(LDAP_LIBLUTIL_A) $(LDAP_LIBLBER_LA)
 XXLIBS  = $(SECURITY_LIBS) $(LUTIL_LIBS)
+RLIBS = $(XRLIBS) $(XXLIBS) $(AC_LIBS) $(XXXLIBS)
+
 
 OBJS     = slapd-common.o
 
@@ -57,3 +61,6 @@ slapd-bind: slapd-bind.o $(OBJS) $(XLIBS)
 ldif-filter: ldif-filter.o $(XLIBS)
        $(LTLINK) -o $@ ldif-filter.o $(LIBS)
 
+slapd-mtread: slapd-mtread.o $(OBJS) $(XRLIBS)
+       $(LTLINK) -o $@ slapd-mtread.o $(OBJS) $(RLIBS)
+
diff --git a/tests/progs/slapd-mtread.c b/tests/progs/slapd-mtread.c
new file mode 100644 (file)
index 0000000..d8f2e8c
--- /dev/null
@@ -0,0 +1,758 @@
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1999-2011 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Kurt Spanier for inclusion
+ * in OpenLDAP Software.
+ */
+
+/*
+ * This tool is a MT reader.  It behaves like slapd-read however
+ * with one or more threads simultaneously using the same connection.
+ * If -M is enabled, then M threads will also perform write operations.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include "ldap_pvt_thread.h"
+
+#include "ac/stdlib.h"
+
+#include "ac/ctype.h"
+#include "ac/param.h"
+#include "ac/socket.h"
+#include "ac/string.h"
+#include "ac/unistd.h"
+#include "ac/wait.h"
+
+#include "ldap.h"
+#include "lutil.h"
+
+#include "ldap_pvt.h"
+
+#include "slapd-common.h"
+
+#define MAXCONN        512
+#define LOOPS  100
+#define RETRIES        0
+#define DEFAULT_BASE   "ou=people,dc=example,dc=com"
+
+static int
+whoami()
+{
+       int me = ldap_pvt_thread_self();
+       return (me);
+}
+
+static void
+do_conn( char *uri, char *manager, struct berval *passwd,
+       LDAP **ld, int nobind, int maxretries, int conn_num );
+
+static void
+do_read( LDAP *ld, char *entry,
+       char **attrs, int noattrs, int nobind, int maxloop,
+       int maxretries, int delay, int force, int chaserefs, int idx );
+
+static void
+do_random( LDAP *ld,
+       char *sbase, char *filter, char **attrs, int noattrs, int nobind,
+       int innerloop, int maxretries, int delay, int force, int chaserefs,
+       int idx );
+
+static void *
+do_onethread( void *arg );
+
+static void *
+do_onerwthread( void *arg );
+
+#define MAX_THREAD     1024
+int    rt_pass[MAX_THREAD];
+int    rt_fail[MAX_THREAD];
+int    rwt_pass[MAX_THREAD];
+int    rwt_fail[MAX_THREAD];
+ldap_pvt_thread_t      rtid[MAX_THREAD], rwtid[MAX_THREAD];
+
+/*
+ * Shared globals (command line args)
+ */
+LDAP           *ld = NULL;
+char           *entry = NULL;
+char           *filter  = NULL;
+int            loops = LOOPS;
+int            outerloops = 1;
+int            retries = RETRIES;
+int            delay = 0;
+int            force = 0;
+int            chaserefs = 0;
+char           *srchattrs[] = { "1.1", NULL };
+char           **attrs = srchattrs;
+int            noattrs = 0;
+int            nobind = 0;
+int            threads = 1;
+int            rwthreads = 0;
+int            verbose = 0;
+
+int            noconns = 1;
+LDAP           **lds = NULL;
+
+static void
+thread_error(char *string)
+{
+       char            thrstr[BUFSIZ];
+
+       snprintf(thrstr, BUFSIZ, "error on tid: %d: %s", whoami(), string);
+       tester_error( thrstr );
+}
+
+static void
+thread_output(char *string)
+{
+       char            thrstr[BUFSIZ];
+
+       snprintf(thrstr, BUFSIZ, "tid: %d says: %s", whoami(), string);
+       tester_error( thrstr );
+}
+
+static void
+thread_verbose(char *string)
+{
+       char            thrstr[BUFSIZ];
+
+       if (!verbose)
+               return;
+       snprintf(thrstr, BUFSIZ, "tid: %d says: %s", whoami(), string);
+       tester_error( thrstr );
+}
+
+static void
+usage( char *name )
+{
+        fprintf( stderr,
+               "usage: %s "
+               "-H <uri> | ([-h <host>] -p <port>) "
+               "-D <manager> "
+               "-w <passwd> "
+               "-e <entry> "
+               "[-A] "
+               "[-C] "
+               "[-F] "
+               "[-N] "
+               "[-v] "
+               "[-c connections] "
+               "[-f filter] "
+               "[-i <ignore>] "
+               "[-l <loops>] "
+               "[-L <outerloops>] "
+               "[-m threads] "
+               "[-M threads] "
+               "[-r <maxretries>] "
+               "[-t <delay>] "
+               "[-T <attrs>] "
+               "[<attrs>] "
+               "\n",
+               name );
+       exit( EXIT_FAILURE );
+}
+
+int
+main( int argc, char **argv )
+{
+       int             i;
+       char            *uri = NULL;
+       char            *host = "localhost";
+       int             port = -1;
+       char            *manager = NULL;
+       struct berval   passwd = { 0, NULL };
+       char            outstr[BUFSIZ];
+       int             ptpass;
+       int             testfail = 0;
+
+
+       tester_init( "slapd-mtread", TESTER_READ );
+
+       /* by default, tolerate referrals and no such object */
+       tester_ignore_str2errlist( "REFERRAL,NO_SUCH_OBJECT" );
+
+       while ( (i = getopt( argc, argv, "ACc:D:e:Ff:H:h:i:L:l:M:m:p:r:t:T:w:v" )) != EOF ) {
+               switch ( i ) {
+               case 'A':
+                       noattrs++;
+                       break;
+
+               case 'C':
+                       chaserefs++;
+                       break;
+
+               case 'H':               /* the server uri */
+                       uri = strdup( optarg );
+                       break;
+
+               case 'h':               /* the servers host */
+                       host = strdup( optarg );
+
+               case 'i':
+                       tester_ignore_str2errlist( optarg );
+                       break;
+
+               case 'N':
+                       nobind++;
+                       break;
+
+               case 'v':
+                       verbose++;
+                       break;
+
+               case 'p':               /* the servers port */
+                       if ( lutil_atoi( &port, optarg ) != 0 ) {
+                               usage( argv[0] );
+                       }
+                       break;
+
+               case 'D':               /* the servers manager */
+                       manager = strdup( optarg );
+                       break;
+
+               case 'w':               /* the server managers password */
+                       passwd.bv_val = strdup( optarg );
+                       passwd.bv_len = strlen( optarg );
+                       memset( optarg, '*', passwd.bv_len );
+                       break;
+
+               case 'c':               /* the number of connections */
+                       if ( lutil_atoi( &noconns, optarg ) != 0 ) {
+                               usage( argv[0] );
+                       }
+                       break;
+
+               case 'e':               /* DN to search for */
+                       entry = strdup( optarg );
+                       break;
+
+               case 'f':               /* the search request */
+                       filter = strdup( optarg );
+                       break;
+
+               case 'F':
+                       force++;
+                       break;
+
+               case 'l':               /* the number of loops */
+                       if ( lutil_atoi( &loops, optarg ) != 0 ) {
+                               usage( argv[0] );
+                       }
+                       break;
+
+               case 'L':               /* the number of outerloops */
+                       if ( lutil_atoi( &outerloops, optarg ) != 0 ) {
+                               usage( argv[0] );
+                       }
+                       break;
+
+               case 'M':               /* the number of R/W threads */
+                       if ( lutil_atoi( &rwthreads, optarg ) != 0 ) {
+                               usage( argv[0] );
+                       }
+                       if (rwthreads > MAX_THREAD)
+                               rwthreads = MAX_THREAD;
+                       break;
+
+               case 'm':               /* the number of threads */
+                       if ( lutil_atoi( &threads, optarg ) != 0 ) {
+                               usage( argv[0] );
+                       }
+                       if (threads > MAX_THREAD)
+                               threads = MAX_THREAD;
+                       break;
+
+               case 'r':               /* the number of retries */
+                       if ( lutil_atoi( &retries, optarg ) != 0 ) {
+                               usage( argv[0] );
+                       }
+                       break;
+
+               case 't':               /* delay in seconds */
+                       if ( lutil_atoi( &delay, optarg ) != 0 ) {
+                               usage( argv[0] );
+                       }
+                       break;
+
+               case 'T':
+                       attrs = ldap_str2charray( optarg, "," );
+                       if ( attrs == NULL ) {
+                               usage( argv[0] );
+                       }
+                       break;
+
+               default:
+                       usage( argv[0] );
+                       break;
+               }
+       }
+
+       if (( entry == NULL ) || ( port == -1 && uri == NULL ))
+               usage( argv[0] );
+
+       if ( *entry == '\0' ) {
+               fprintf( stderr, "%s: invalid EMPTY entry DN.\n",
+                               argv[0] );
+               exit( EXIT_FAILURE );
+       }
+
+       if ( argv[optind] != NULL ) {
+               attrs = &argv[optind];
+       }
+
+       if (noconns < 1)
+               noconns = 1;
+       if (noconns > MAXCONN)
+               noconns = MAXCONN;
+       lds = (LDAP **) calloc( sizeof(LDAP *), noconns);
+       if (lds == NULL) {
+               fprintf( stderr, "%s: Memory error: calloc noconns.\n",
+                               argv[0] );
+               exit( EXIT_FAILURE );
+       }
+
+       uri = tester_uri( uri, host, port );
+       /* One connection and one connection only */
+       do_conn( uri, manager, &passwd, &ld, nobind, retries, 0 );
+       lds[0] = ld;
+       for(i = 1; i < noconns; i++) {
+               do_conn( uri, manager, &passwd, &lds[i], nobind, retries, i );
+       }
+
+       ldap_pvt_thread_initialize();
+
+       snprintf(outstr, BUFSIZ, "MT Test Start: conns: %d (%s)", noconns, uri);
+       tester_error(outstr);
+       snprintf(outstr, BUFSIZ, "Threads: RO: %d RW: %d", threads, rwthreads);
+       tester_error(outstr);
+
+       /* Set up read only threads */
+       for ( i = 0; i < threads; i++ ) {
+               ldap_pvt_thread_create( &rtid[i], 0, do_onethread, &rtid[i]);
+               snprintf(outstr, BUFSIZ, "Created RO thread %d [%d]", i, (int)rtid[i]);
+               thread_verbose(outstr);
+       }
+       /* Set up read/write threads */
+       for ( i = 0; i < rwthreads; i++ ) {
+               ldap_pvt_thread_create( &rwtid[i], 0, do_onerwthread, &rwtid[i]);
+               snprintf(outstr, BUFSIZ, "Created RW thread %d [%d]", i, (int)rwtid[i]);
+               thread_verbose(outstr);
+       }
+
+       ptpass =  outerloops * loops;
+
+       /* wait for read only threads to complete */
+       for ( i = 0; i < threads; i++ )
+               ldap_pvt_thread_join(rtid[i], NULL);
+       /* wait for read/write threads to complete */
+       for ( i = 0; i < rwthreads; i++ )
+               ldap_pvt_thread_join(rwtid[i], NULL);
+
+       for(i = 0; i < noconns; i++) {
+               if ( lds[i] != NULL ) {
+                       ldap_unbind_ext( lds[i], NULL, NULL );
+               }
+       }
+       free( lds );
+
+       for ( i = 0; i < threads; i++ ) {
+               snprintf(outstr, BUFSIZ, "RO thread %d pass=%d fail=%d", i,
+                       rt_pass[i], rt_fail[i]);
+               tester_error(outstr);
+               if (rt_fail[i] != 0 || rt_pass[i] != ptpass) {
+                       snprintf(outstr, BUFSIZ, "FAIL RO thread %d", i);
+                       tester_error(outstr);
+                       testfail++;
+               }
+       }
+       for ( i = 0; i < rwthreads; i++ ) {
+               snprintf(outstr, BUFSIZ, "RW thread %d pass=%d fail=%d", i,
+                       rwt_pass[i], rwt_fail[i]);
+               tester_error(outstr);
+               if (rwt_fail[i] != 0 || rwt_pass[i] != ptpass) {
+                       snprintf(outstr, BUFSIZ, "FAIL RW thread %d", i);
+                       tester_error(outstr);
+                       testfail++;
+               }
+       }
+       snprintf(outstr, BUFSIZ, "MT Test complete" );
+       tester_error(outstr);
+
+       if (testfail)
+               exit( EXIT_FAILURE );
+       exit( EXIT_SUCCESS );
+}
+
+static void *
+do_onethread( void *arg )
+{
+       int             i, j, thisconn;
+       LDAP            **mlds;
+       int             me = whoami();
+       char            thrstr[BUFSIZ];
+       int             rc, refcnt = 0;
+       int             myidx = (ldap_pvt_thread_t *)arg - rtid;
+
+       mlds = (LDAP **) calloc( sizeof(LDAP *), noconns);
+       if (mlds == NULL) {
+               thread_error( "Memory error: thread calloc for noconns" );
+               exit( EXIT_FAILURE );
+       }
+
+       for ( j = 0; j < outerloops; j++ ) {
+               for(i = 0; i < noconns; i++) {
+                       mlds[i] = ldap_dup(lds[i]);
+                       if (mlds[i] == NULL) {
+                               thread_error( "ldap_dup error" );
+                       }
+               }
+               rc = ldap_get_option(mlds[0], LDAP_OPT_SESSION_REFCNT, &refcnt);
+               snprintf(thrstr, BUFSIZ,
+                       "RO Thread: %d conns: %d refcnt: %d (rc = %d)",
+                       me, noconns, refcnt, rc);
+               thread_verbose(thrstr);
+
+               thisconn = (me + j) % noconns;
+               if (thisconn < 0 || thisconn >= noconns)
+                       thisconn = 0;
+               if (mlds[thisconn] == NULL) {
+                       thread_error("(failed to dup)");
+                       tester_perror( "ldap_dup", "(failed to dup)" );
+                       exit( EXIT_FAILURE );
+               }
+               snprintf(thrstr, BUFSIZ, "Thread %d using conn %d", me, thisconn);
+               thread_verbose(thrstr);
+               if ( filter != NULL ) {
+                       do_random( mlds[thisconn], entry, filter, attrs,
+                               noattrs, nobind, loops, retries, delay, force,
+                               chaserefs, myidx );
+
+               } else {
+                       do_read( mlds[thisconn], entry, attrs,
+                               noattrs, nobind, loops, retries, delay, force,
+                               chaserefs, myidx );
+               }
+               for(i = 0; i < noconns; i++) {
+                       (void) ldap_destroy(mlds[i]);
+                       mlds[i] = NULL;
+               }
+       }
+       free( mlds );
+       return( NULL );
+}
+
+static void *
+do_onerwthread( void *arg )
+{
+       int             i, j, thisconn;
+       LDAP            **mlds, *ld;
+       int             me = whoami();
+       char            thrstr[BUFSIZ];
+       char            dn[256], uids[32], cns[32], *base;
+       LDAPMod         *attrp[5], attrs[4];
+       char            *oc_vals[] = { "top", "OpenLDAPperson", NULL };
+       char            *cn_vals[] = { NULL, NULL };
+       char            *sn_vals[] = { NULL, NULL };
+       char            *uid_vals[] = { NULL, NULL };
+       int             ret;
+       int             adds = 0;
+       int             dels = 0;
+       int             rc, refcnt = 0;
+       int             myidx = (ldap_pvt_thread_t *)arg - rwtid;
+
+       mlds = (LDAP **) calloc( sizeof(LDAP *), noconns);
+       if (mlds == NULL) {
+               thread_error( "Memory error: thread calloc for noconns" );
+               exit( EXIT_FAILURE );
+       }
+
+       snprintf(uids, 32, "rwtest%04.4d", me);
+       snprintf(cns, 32, "rwtest%04.4d", me);
+       /* add setup */
+       for (i = 0; i < 4; i++) {
+               attrp[i] = &attrs[i];
+               attrs[i].mod_op = 0;
+       }
+       attrp[4] = NULL;
+       attrs[0].mod_type = "objectClass";
+       attrs[0].mod_values = oc_vals;
+       attrs[1].mod_type = "cn";
+       attrs[1].mod_values = cn_vals;
+       cn_vals[0] = &cns[0];
+       attrs[2].mod_type = "sn";
+       attrs[2].mod_values = sn_vals;
+       sn_vals[0] = &cns[0];
+       attrs[3].mod_type = "uid";
+       attrs[3].mod_values = uid_vals;
+       uid_vals[0] = &uids[0];
+
+       for ( j = 0; j < outerloops; j++ ) {
+               for(i = 0; i < noconns; i++) {
+                       mlds[i] = ldap_dup(lds[i]);
+                       if (mlds[i] == NULL) {
+                               thread_error( "ldap_dup error" );
+                       }
+               }
+               rc = ldap_get_option(mlds[0], LDAP_OPT_SESSION_REFCNT, &refcnt);
+               snprintf(thrstr, BUFSIZ,
+                       "RW Thread: %d conns: %d refcnt: %d (rc = %d)",
+                       me, noconns, refcnt, rc);
+               thread_verbose(thrstr);
+
+               thisconn = (me + j) % noconns;
+               if (thisconn < 0 || thisconn >= noconns)
+                       thisconn = 0;
+               if (mlds[thisconn] == NULL) {
+                       thread_error("(failed to dup)");
+                       tester_perror( "ldap_dup", "(failed to dup)" );
+                       exit( EXIT_FAILURE );
+               }
+               snprintf(thrstr, BUFSIZ, "START RW Thread %d using conn %d",
+                       me, thisconn);
+               thread_verbose(thrstr);
+
+               ld = mlds[thisconn];
+               if (entry != NULL)
+                       base = entry;
+               else
+                       base = DEFAULT_BASE;
+               snprintf(dn, 256, "cn=%s,%s", cns, base);
+
+               adds = 0;
+               dels = 0;
+               for (i = 0; i < loops; i++) {
+                       ret = ldap_add_ext_s(ld, dn, &attrp[0], NULL, NULL);
+                       if (ret == LDAP_SUCCESS) {
+                               adds++;
+                               ret = ldap_delete_ext_s(ld, dn, NULL, NULL);
+                               if (ret == LDAP_SUCCESS) {
+                                       dels++;
+                                       rwt_pass[myidx]++;
+                               } else {
+                                       thread_output(ldap_err2string(ret));
+                                       rwt_fail[myidx]++;
+                               }
+                       } else {
+                               thread_output(ldap_err2string(ret));
+                               rwt_fail[myidx]++;
+                       }
+               }
+
+               snprintf(thrstr, BUFSIZ,
+                       "INNER STOP RW Thread %d using conn %d (%d/%d)",
+                       me, thisconn, adds, dels);
+               thread_verbose(thrstr);
+
+               for(i = 0; i < noconns; i++) {
+                       (void) ldap_destroy(mlds[i]);
+                       mlds[i] = NULL;
+               }
+       }
+
+       free( mlds );
+       return( NULL );
+}
+
+static void
+do_conn( char *uri, char *manager, struct berval *passwd,
+       LDAP **ldp, int nobind, int maxretries, int conn_num )
+{
+       LDAP    *ld = NULL;
+       int     version = LDAP_VERSION3;
+       int     i = 0, do_retry = maxretries;
+       int     rc = LDAP_SUCCESS;
+       char    thrstr[BUFSIZ];
+
+retry:;
+       ldap_initialize( &ld, uri );
+       if ( ld == NULL ) {
+               snprintf( thrstr, BUFSIZ, "connection: %d", conn_num );
+               tester_error( thrstr );
+               tester_perror( "ldap_initialize", NULL );
+               exit( EXIT_FAILURE );
+       }
+
+       (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version ); 
+       (void) ldap_set_option( ld, LDAP_OPT_REFERRALS,
+               chaserefs ? LDAP_OPT_ON : LDAP_OPT_OFF );
+
+       if ( do_retry == maxretries ) {
+               snprintf( thrstr, BUFSIZ, "do_conn #%d\n", conn_num );
+               thread_verbose( thrstr );
+       }
+
+       if ( nobind == 0 ) {
+               rc = ldap_sasl_bind_s( ld, manager, LDAP_SASL_SIMPLE, passwd, NULL, NULL, NULL );
+               if ( rc != LDAP_SUCCESS ) {
+                       snprintf( thrstr, BUFSIZ, "connection: %d", conn_num );
+                       tester_error( thrstr );
+                       tester_ldap_error( ld, "ldap_sasl_bind_s", NULL );
+                       switch ( rc ) {
+                       case LDAP_BUSY:
+                       case LDAP_UNAVAILABLE:
+                               if ( do_retry > 0 ) {
+                                       ldap_unbind_ext( ld, NULL, NULL );
+                                       ld = NULL;
+                                       do_retry--;
+                                       if ( delay != 0 ) {
+                                           sleep( delay );
+                                       }
+                                       goto retry;
+                               }
+                       /* fallthru */
+                       default:
+                               break;
+                       }
+                       exit( EXIT_FAILURE );
+               }
+       }
+       *ldp = ld;
+}
+
+static void
+do_random( LDAP *ld,
+       char *sbase, char *filter, char **srchattrs, int noattrs, int nobind,
+       int innerloop, int maxretries, int delay, int force, int chaserefs,
+       int idx )
+{
+       int     i = 0, do_retry = maxretries;
+       char    *attrs[ 2 ];
+       int     rc = LDAP_SUCCESS;
+       int     nvalues = 0;
+       char    **values = NULL;
+       LDAPMessage *res = NULL, *e = NULL;
+       char    thrstr[BUFSIZ];
+
+       attrs[ 0 ] = LDAP_NO_ATTRS;
+       attrs[ 1 ] = NULL;
+
+       snprintf( thrstr, BUFSIZ,
+                       "Read(%d): base=\"%s\", filter=\"%s\".\n",
+                       innerloop, sbase, filter );
+       thread_verbose( thrstr );
+
+       rc = ldap_search_ext_s( ld, sbase, LDAP_SCOPE_SUBTREE,
+               filter, attrs, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &res );
+       switch ( rc ) {
+       case LDAP_SIZELIMIT_EXCEEDED:
+       case LDAP_TIMELIMIT_EXCEEDED:
+       case LDAP_SUCCESS:
+               nvalues = ldap_count_entries( ld, res );
+               if ( nvalues == 0 ) {
+                       if ( rc ) {
+                               tester_ldap_error( ld, "ldap_search_ext_s", NULL );
+                       }
+                       break;
+               }
+
+               values = malloc( ( nvalues + 1 ) * sizeof( char * ) );
+               for ( i = 0, e = ldap_first_entry( ld, res ); e != NULL; i++, e = ldap_next_entry( ld, e ) )
+               {
+                       values[ i ] = ldap_get_dn( ld, e );
+               }
+               values[ i ] = NULL;
+
+               ldap_msgfree( res );
+
+               if ( do_retry == maxretries ) {
+                       snprintf( thrstr, BUFSIZ,
+                               "Read base=\"%s\" filter=\"%s\" got %d values.\n",
+                               sbase, filter, nvalues );
+                       thread_verbose( thrstr );
+               }
+
+               for ( i = 0; i < innerloop; i++ ) {
+                       int     r = ((double)nvalues)*rand()/(RAND_MAX + 1.0);
+
+                       do_read( ld, values[ r ],
+                               srchattrs, noattrs, nobind, 1, maxretries,
+                               delay, force, chaserefs, idx );
+               }
+               for( i = 0; i < nvalues; i++) {
+                       if (values[i] != NULL)
+                               ldap_memfree( values[i] );
+               }
+               free( values );
+               break;
+
+       default:
+               tester_ldap_error( ld, "ldap_search_ext_s", NULL );
+               break;
+       }
+
+       snprintf( thrstr, BUFSIZ, "Search done (%d).\n", rc );
+       thread_verbose( thrstr );
+}
+
+static void
+do_read( LDAP *ld, char *entry,
+       char **attrs, int noattrs, int nobind, int maxloop,
+       int maxretries, int delay, int force, int chaserefs, int idx )
+{
+       int     i = 0, do_retry = maxretries;
+       int     rc = LDAP_SUCCESS;
+       char    thrstr[BUFSIZ];
+
+retry:;
+       if ( do_retry == maxretries ) {
+               snprintf( thrstr, BUFSIZ, "Read(%d): entry=\"%s\".\n",
+                       maxloop, entry );
+               thread_verbose( thrstr );
+       }
+
+       snprintf(thrstr, BUFSIZ, "tid: %d LD %p cnt: %d (retried %d) (%s)", \
+                whoami(), (void *) ld, maxloop, (do_retry - maxretries), entry);
+       thread_verbose( thrstr );
+
+       for ( ; i < maxloop; i++ ) {
+               LDAPMessage *res = NULL;
+
+               rc = ldap_search_ext_s( ld, entry, LDAP_SCOPE_BASE,
+                               NULL, attrs, noattrs, NULL, NULL, NULL,
+                               LDAP_NO_LIMIT, &res );
+               if ( res != NULL ) {
+                       ldap_msgfree( res );
+               }
+
+               if ( rc == 0 ) {
+                       rt_pass[idx]++;
+               } else {
+                       int             first = tester_ignore_err( rc );
+                       char            buf[ BUFSIZ ];
+
+                       rt_fail[idx]++;
+                       snprintf( buf, sizeof( buf ), "ldap_search_ext_s(%s)", entry );
+
+                       /* if ignore.. */
+                       if ( first ) {
+                               /* only log if first occurrence */
+                               if ( ( force < 2 && first > 0 ) || abs(first) == 1 ) {
+                                       tester_ldap_error( ld, buf, NULL );
+                               }
+                               continue;
+                       }
+
+                       /* busy needs special handling */
+                       tester_ldap_error( ld, buf, NULL );
+                       if ( rc == LDAP_BUSY && do_retry > 0 ) {
+                               do_retry--;
+                               goto retry;
+                       }
+                       break;
+               }
+       }
+}
index 5871ea51a2611b7a90be06033235f9bcf8800c9a..6086de52ca869e053fc602f4d80549cd0ac85b6e 100755 (executable)
@@ -192,6 +192,7 @@ LDAPCOMPARE="$CLIENTDIR/ldapcompare $TOOLARGS"
 LDAPEXOP="$CLIENTDIR/ldapexop $TOOLARGS"
 SLAPDTESTER=$PROGDIR/slapd-tester
 LDIFFILTER=$PROGDIR/ldif-filter
+SLAPDMTREAD=$PROGDIR/slapd-mtread
 LVL=${SLAPD_DEBUG-0x4105}
 LOCALHOST=localhost
 BASEPORT=${SLAPD_BASEPORT-9010}
@@ -311,6 +312,8 @@ SLAVE2OUT=$SERVER3OUT
 SLAVEFLT=$SERVER2FLT
 SLAVE2FLT=$SERVER3FLT
 
+MTREADOUT=$TESTDIR/mtread.out
+
 # original outputs for cmp
 PROXYCACHEOUT=$DATADIR/proxycache.out
 REFERRALOUT=$DATADIR/referrals.out
diff --git a/tests/scripts/test060-mt-hot b/tests/scripts/test060-mt-hot
new file mode 100755 (executable)
index 0000000..afb019e
--- /dev/null
@@ -0,0 +1,297 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2011 The OpenLDAP Foundation.
+## All rights reserved.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted only as authorized by the OpenLDAP
+## Public License.
+##
+## A copy of this license is available in the file LICENSE in the
+## top-level directory of the distribution or, alternatively, at
+## <http://www.OpenLDAP.org/license.html>.
+
+# The default debug level logs more than 1Gb:
+SLAPD_DEBUG=${SLAPD_DEBUG_MT_HOT-stats}
+
+echo "running defines.sh"
+. $SRCDIR/scripts/defines.sh
+
+if test $MONITORDB = "no" ; then 
+       echo "Monitor backend not available, test skipped"
+       exit 0
+fi 
+
+mkdir -p $TESTDIR $DBDIR1
+
+#
+# Populate and start up slapd server with some random data
+#
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND $MONITORDB < $MCONF > $ADDCONF
+$SLAPADD -f $ADDCONF -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+       echo "slapadd failed ($RC)!"
+       exit $RC
+fi
+
+echo "Running slapindex to index slapd database..."
+. $CONFFILTER $BACKEND $MONITORDB < $CONF > $CONF1
+$SLAPINDEX -f $CONF1
+RC=$?
+if test $RC != 0 ; then
+       echo "warning: slapindex failed ($RC)"
+       echo "  assuming no indexing support"
+fi
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+echo $SLAPD -f $CONF1 -h $URI1 -d $LVL $TIMING
+$SLAPD -f $CONF1 -h $URI1 -d $LVL $TIMING > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+    echo PID $PID
+    read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+# Perform a basic search, make sure of a functional setup
+echo "Testing basic monitor search..."
+for i in 0 1 2 3 4 5; do
+       $LDAPSEARCH -s base -b "$MONITORDN" -H $URI1 \
+               '(objectclass=*)' > /dev/null 2>&1
+       RC=$?
+       if test $RC = 0 ; then
+               break
+       fi
+       echo "Waiting 5 seconds for slapd to start..."
+       sleep 5
+done
+
+if test $RC != 0 ; then
+       echo "mt-hot read failed ($RC)!"
+       test $KILLSERVERS != no && kill -HUP $KILLPIDS
+       exit $RC
+fi
+
+cat /dev/null > $MTREADOUT
+
+echo "Monitor searches"
+# Perform a basic single threaded search on a single connection
+THR=1
+OUTER=1
+INNER=50000
+echo "Testing basic mt-hot search: $THR threads ($OUTER x $INNER) loops..."
+echo $SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+       -e "$MONITORDN" \
+       -m $THR -L $OUTER -l $INNER
+$SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+       -e "$MONITORDN" -f "(objectclass=*)" \
+       -m $THR -L $OUTER -l $INNER >> $MTREADOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+       echo "slapd-mtread failed ($RC)!"
+       test $KILLSERVERS != no && kill -HUP $KILLPIDS
+       exit $RC
+fi
+
+# Perform a basic multi-threaded search on a single connection
+THR=5
+OUTER=1
+INNER=10000
+echo "Testing basic mt-hot search: $THR threads ($OUTER x $INNER) loops..."
+echo $SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+       -e "$MONITORDN" \
+       -m $THR -L $OUTER -l $INNER
+$SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+       -e "$MONITORDN" -f "(objectclass=*)" \
+       -m $THR -L $OUTER -l $INNER >> $MTREADOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+       echo "slapd-mtread failed ($RC)!"
+       test $KILLSERVERS != no && kill -HUP $KILLPIDS
+       exit $RC
+fi
+
+# Perform a basic multi-threaded search on a single connection
+THR=100
+OUTER=5
+INNER=100
+echo "Testing basic mt-hot search: $THR threads ($OUTER x $INNER) loops..."
+echo $SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+       -e "$MONITORDN" \
+       -m $THR -L $OUTER -l $INNER
+$SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+       -e "$MONITORDN" -f "(objectclass=*)" \
+       -m $THR -L $OUTER -l $INNER >> $MTREADOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+       echo "slapd-mtread failed ($RC)!"
+       test $KILLSERVERS != no && kill -HUP $KILLPIDS
+       exit $RC
+fi
+
+# Perform a single threaded random DB search on a single connection
+echo "Random searches"
+THR=1
+OUTER=1
+INNER=50000
+echo "Testing random mt-hot search: $THR threads ($OUTER x $INNER) loops..."
+echo $SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+       -e "$BASEDN" -f "(objectclass=*)" \
+       -m $THR -L $OUTER -l $INNER
+$SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+       -e "$BASEDN" -f "(objectclass=*)" \
+       -m $THR -L $OUTER -l $INNER >> $MTREADOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+       echo "slapd-mtread failed ($RC)!"
+       test $KILLSERVERS != no && kill -HUP $KILLPIDS
+       exit $RC
+fi
+
+# Perform a multi-threaded random DB search on a single connection
+THR=5
+OUTER=1
+INNER=10000
+echo "Testing random mt-hot search: $THR threads ($OUTER x $INNER) loops..."
+echo $SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+       -e "$BASEDN" -f "(objectclass=*)" \
+       -m $THR -L $OUTER -l $INNER
+$SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+       -e "$BASEDN" -f "(objectclass=*)" \
+       -m $THR -L $OUTER -l $INNER >> $MTREADOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+       echo "slapd-mtread failed ($RC)!"
+       test $KILLSERVERS != no && kill -HUP $KILLPIDS
+       exit $RC
+fi
+
+# Perform a multi-threaded random DB search on a single connection
+THR=100
+OUTER=5
+INNER=100
+echo "Testing random mt-hot search: $THR threads ($OUTER x $INNER) loops..."
+echo $SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+       -e "$BASEDN" -f "(objectclass=*)" \
+       -m $THR -L $OUTER -l $INNER
+$SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+       -e "$BASEDN" -f "(objectclass=*)" \
+       -m $THR -L $OUTER -l $INNER >> $MTREADOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+       echo "slapd-mtread failed ($RC)!"
+       test $KILLSERVERS != no && kill -HUP $KILLPIDS
+       exit $RC
+fi
+
+# Perform a basic multi-threaded search using multiple connections
+echo "Multiple threads and connection searches"
+CONN=5
+THR=5
+OUTER=1
+INNER=10000
+echo "Testing basic mt-hot search: $THR threads $CONN conns ($OUTER x $INNER) loops..."
+echo $SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+       -e "$MONITORDN" \
+       -c $CONN -m $THR -L $OUTER -l $INNER
+$SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+       -e "$MONITORDN" -f "(objectclass=*)" \
+       -c $CONN -m $THR -L $OUTER -l $INNER >> $MTREADOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+       echo "slapd-mtread failed ($RC)!"
+       test $KILLSERVERS != no && kill -HUP $KILLPIDS
+       exit $RC
+fi
+
+# Perform a basic multi-threaded search using multiple connections
+CONN=5
+THR=50
+OUTER=5
+INNER=1000
+echo "Testing basic mt-hot search: $THR threads $CONN conns ($OUTER x $INNER) loops..."
+echo $SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+       -e "$MONITORDN" \
+       -c $CONN -m $THR -L $OUTER -l $INNER
+$SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+       -e "$MONITORDN" -f "(objectclass=*)" \
+       -c $CONN -m $THR -L $OUTER -l $INNER >> $MTREADOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+       echo "slapd-mtread failed ($RC)!"
+       test $KILLSERVERS != no && kill -HUP $KILLPIDS
+       exit $RC
+fi
+
+# Perform a multi-threaded random DB search using multiple connections
+CONN=5
+THR=100
+OUTER=5
+INNER=100
+echo "Testing random mt-hot search: $THR threads $CONN conns ($OUTER x $INNER) loops..."
+echo $SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+       -e "$BASEDN" -f "(objectclass=*)" \
+       -c $CONN -m $THR -L $OUTER -l $INNER
+$SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+       -e "$BASEDN" -f "(objectclass=*)" \
+       -c $CONN -m $THR -L $OUTER -l $INNER >> $MTREADOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+       echo "slapd-mtread failed ($RC)!"
+       test $KILLSERVERS != no && kill -HUP $KILLPIDS
+       exit $RC
+fi
+
+# Perform a multi-threaded random reads and writes using single connection
+CONN=1
+THR=10
+WTHR=10
+OUTER=5
+INNER=100
+echo "Testing random mt-hot r/w search: $THR read threads $WTHR write threads $CONN conns ($OUTER x $INNER) loops..."
+echo $SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+       -e "$BASEDN" -f "(&(!(cn=rwtest*))(objectclass=*))" \
+       -c $CONN -m $THR -M $WTHR -L $OUTER -l $INNER
+$SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+       -e "$BASEDN" -f "(&(!(cn=rwtest*))(objectclass=*))" \
+       -c $CONN -m $THR -M $WTHR -L $OUTER -l $INNER >> $MTREADOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+       echo "slapd-mtread failed ($RC)!"
+       test $KILLSERVERS != no && kill -HUP $KILLPIDS
+       exit $RC
+fi
+
+# Perform a multi-threaded random reads and writes using multiple connections
+CONN=5
+THR=10
+WTHR=10
+OUTER=5
+INNER=100
+echo "Testing random mt-hot r/w search: $THR read threads $WTHR write threads $CONN conns ($OUTER x $INNER) loops..."
+echo $SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+       -e "$BASEDN" -f "(&(!(cn=rwtest*))(objectclass=*))" \
+       -c $CONN -m $THR -M $WTHR -L $OUTER -l $INNER
+$SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+       -e "$BASEDN" -f "(&(!(cn=rwtest*))(objectclass=*))" \
+       -c $CONN -m $THR -M $WTHR -L $OUTER -l $INNER >> $MTREADOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+       echo "slapd-mtread failed ($RC)!"
+       test $KILLSERVERS != no && kill -HUP $KILLPIDS
+       exit $RC
+fi
+
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+
+exit 0
diff --git a/tests/scripts/test061-syncreplication-initiation b/tests/scripts/test061-syncreplication-initiation
new file mode 100755 (executable)
index 0000000..d2b3379
--- /dev/null
@@ -0,0 +1,668 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2011 The OpenLDAP Foundation.
+## All rights reserved.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted only as authorized by the OpenLDAP
+## Public License.
+##
+## A copy of this license is available in the file LICENSE in the
+## top-level directory of the distribution or, alternatively, at
+## <http://www.OpenLDAP.org/license.html>.
+
+# This script tests race conditions related to setting up the syncrepl
+# refresh phase, especially when the provider is itself a consumer
+# refreshing from its provider again.
+
+# The configuration used is a provider->forwarder->consumer chain, where
+# the forwarder is restarted between add/delete of entries on the provider.
+
+echo "Running defines.sh"
+. $SRCDIR/scripts/defines.sh
+
+test "x$INITIATION_RACE_TESTS" = "x" && INITIATION_RACE_TESTS=1
+
+if test $SYNCPROV = syncprovno; then
+       echo "Syncrepl provider overlay not available, test skipped"
+       exit 0
+fi
+
+RETRY="1 +"
+
+PROV_DIR=$TESTDIR/prov
+CONS_DIR=$TESTDIR/cons
+FWD1_DIR=$TESTDIR/fwd1
+FWD2_DIR=$TESTDIR/fwd2
+
+PROV_URI=$URI1
+CONS_URI=$URI2
+FWD1_URI=$URI3
+
+PROV_LOG=$LOG1
+CONS_LOG=$LOG2
+FWD1_LOG=$LOG3
+
+DIRS="$PROV_DIR $CONS_DIR $FWD1_DIR"
+URIS="$PROV_URI $CONS_URI $FWD1_URI"
+
+noObj=32
+nullExclude="" nullOK=""
+test $BACKEND = null && nullExclude="# " nullOK="OK" noObj=0
+
+mkdir -p $TESTDIR
+
+for dir in $DIRS; do
+       mkdir -p $dir $dir/slapd.d $dir/db
+done
+
+KILLPIDS=
+
+$SLAPPASSWD -g -n >$CONFIGPWF
+
+case "$BACKEND" in
+       bdb|hdb)        olcDbCheckpoint="olcDbCheckpoint";;
+       *)              olcDbCheckpoint="# olcDbCheckpoint";;
+esac
+
+echo "Initializing server configurations"
+for dir in $DIRS; do
+       $SLAPADD -F $dir/slapd.d -n 0 <<EOF
+dn: cn=config
+objectClass: olcGlobal
+cn: config
+olcServerID: 1 $PROV_URI
+olcServerID: 2 $CONS_URI
+olcServerID: 3 $FWD1_URI
+
+dn: olcDatabase={0}config,cn=config
+objectClass: olcDatabaseConfig
+olcDatabase: {0}config
+olcRootPW:< file://$CONFIGPWF
+
+EOF
+done
+
+echo "Starting provider slapd on $PROV_URI"
+cd $PROV_DIR
+$SLAPD -F slapd.d -h $PROV_URI -d $LVL $TIMING >> $PROV_LOG 2>&1 &
+PROV_PID=$!
+if test $WAIT != 0 ; then
+       echo PID $PROV_PID
+       read foo
+fi
+KILLPIDS="$KILLPIDS $PROV_PID"
+cd $TESTWD
+sleep 1
+for i in 1 2 3 4 5; do
+       $LDAPSEARCH -s base -b "" -H $PROV_URI \
+               'objectclass=*' > /dev/null 2>&1
+       RC=$?
+       test $RC = 0 && break
+       echo "Waiting $i seconds for slapd to start..."
+       sleep $i
+done
+if test $RC != 0 ; then
+       echo "ldapsearch failed ($RC)!"
+       test $KILLSERVERS != no && kill -HUP $KILLPIDS
+       exit $RC
+fi
+
+echo "Starting forward1 slapd on $FWD1_URI"
+cd $FWD1_DIR
+$SLAPD -F slapd.d -h $FWD1_URI -d $LVL $TIMING >> $FWD1_LOG 2>&1 &
+FWD1_PID=$!
+if test $WAIT != 0 ; then
+       echo PID $FWD1_PID
+       read foo
+fi
+KILLPIDS="$KILLPIDS $FWD1_PID"
+cd $TESTWD
+sleep 1
+for i in 1 2 3 4 5; do
+       $LDAPSEARCH -s base -b "" -H $FWD1_URI \
+               'objectclass=*' > /dev/null 2>&1
+       RC=$?
+       test $RC = 0 && break
+       echo "Waiting $i seconds for slapd to start..."
+       sleep $i
+done
+if test $RC != 0 ; then
+       echo "ldapsearch failed ($RC)!"
+       test $KILLSERVERS != no && kill -HUP $KILLPIDS
+       exit $RC
+fi
+
+echo "Starting consumer slapd on $CONS_URI"
+cd $CONS_DIR
+$SLAPD -F slapd.d -h $CONS_URI -d $LVL $TIMING >> $CONS_LOG 2>&1 &
+CONS_PID=$!
+if test $WAIT != 0 ; then
+       echo PID $CONS_PID
+       read foo
+fi
+KILLPIDS="$KILLPIDS $CONS_PID"
+cd $TESTWD
+sleep 1
+for i in 1 2 3 4 5; do
+       $LDAPSEARCH -s base -b "" -H $CONS_URI \
+               'objectclass=*' > /dev/null 2>&1
+       RC=$?
+       test $RC = 0 && break
+       echo "Waiting $i seconds for slapd to start..."
+       sleep $i
+done
+if test $RC != 0 ; then
+       echo "ldapsearch failed ($RC)!"
+       test $KILLSERVERS != no && kill -HUP $KILLPIDS
+       exit $RC
+fi
+
+for uri in $URIS; do
+       echo "Adding schema on $uri"
+       $LDAPADD -D cn=config -H $uri -y $CONFIGPWF <<EOF > $TESTOUT 2>&1
+include: file://$ABS_SCHEMADIR/core.ldif
+
+include: file://$ABS_SCHEMADIR/cosine.ldif
+
+include: file://$ABS_SCHEMADIR/inetorgperson.ldif
+
+include: file://$ABS_SCHEMADIR/openldap.ldif
+
+include: file://$ABS_SCHEMADIR/nis.ldif
+
+EOF
+       RC=$?
+       if test $RC != 0 ; then
+               echo "ldapadd failed ($RC)!"
+               test $KILLSERVERS != no && kill -HUP $KILLPIDS
+               exit $RC
+       fi
+
+       [ "$BACKENDTYPE" = mod ] || continue
+
+       echo "Adding backend module on $uri..."
+       $LDAPADD -D cn=config -H $uri -y $CONFIGPWF <<EOF >>$TESTOUT 2>&1
+dn: cn=module,cn=config
+objectClass: olcModuleList
+cn: module
+olcModulePath: ../../../servers/slapd/back-$BACKEND
+olcModuleLoad: back_$BACKEND.la
+
+EOF
+       RC=$?
+       if test $RC != 0 ; then
+               echo "ldapadd failed for backend module ($RC)!"
+               test $KILLSERVERS != no && kill -HUP $KILLPIDS
+               exit $RC
+       fi
+done
+
+syncprov_module=''
+[ "$AC_syncprov" = syncprovmod ] && syncprov_module='
+dn: cn=module,cn=config
+objectClass: olcModuleList
+cn: module
+olcModulePath: ../../../servers/slapd/overlays
+olcModuleLoad: syncprov.la'
+
+for uri in $PROV_URI; do
+       echo "Adding database configuration on $uri"
+       $LDAPADD -D cn=config -H $uri -y $CONFIGPWF <<EOF > $TESTOUT 2>&1
+dn: olcDatabase={1}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+objectClass: olc${BACKEND}Config
+olcDatabase: {1}$BACKEND
+${nullExclude}olcDbDirectory: ./db
+$olcDbCheckpoint: 1024 5
+olcSuffix: $BASEDN
+olcRootDN: $MANAGERDN
+olcRootPW: $PASSWD
+
+$syncprov_module
+
+dn: olcOverlay={0}syncprov,olcDatabase={1}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+objectClass: olcSyncProvConfig
+olcOverlay: {0}syncprov
+olcSpCheckpoint: 1 1
+
+EOF
+       RC=$?
+       if test $RC != 0 ; then
+               echo "ldapadd failed ($RC)!"
+               test $KILLSERVERS != no && kill -HUP $KILLPIDS
+               exit $RC
+       fi
+
+       echo "Populating provider on $uri"
+       $LDAPADD -D "$MANAGERDN" -H $PROV_URI -w $PASSWD <<EOF >> $TESTOUT 2>&1
+dn: $BASEDN
+objectClass: top
+objectClass: organization
+objectClass: dcObject
+dc: example
+o: Example, Inc
+
+EOF
+       RC=$?
+       if test $RC != 0 ; then
+               echo "ldapadd failed ($RC)!"
+               test $KILLSERVERS != no && kill -HUP $KILLPIDS
+               exit $RC
+       fi
+done
+
+for uri in $FWD1_URI; do
+       echo "Adding database configuration on $uri"
+       $LDAPADD -D cn=config -H $uri -y $CONFIGPWF <<EOF > $TESTOUT 2>&1
+dn: olcDatabase={1}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+objectClass: olc${BACKEND}Config
+olcDatabase: {1}$BACKEND
+${nullExclude}olcDbDirectory: ./db
+$olcDbCheckpoint: 1024 5
+olcSuffix: $BASEDN
+olcRootDN: $MANAGERDN
+olcRootPW: $PASSWD
+olcSyncRepl: rid=1 provider=$PROV_URI searchbase="$BASEDN"
+  binddn="$MANAGERDN" bindmethod=simple credentials=$PASSWD
+  type=refreshAndPersist retry="$RETRY" timeout=1
+
+$syncprov_module
+
+dn: olcOverlay={0}syncprov,olcDatabase={1}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+objectClass: olcSyncProvConfig
+olcOverlay: {0}syncprov
+olcSpCheckpoint: 1 1
+
+EOF
+       RC=$?
+       if test $RC != 0 ; then
+               echo "ldapadd failed ($RC)!"
+               test $KILLSERVERS != no && kill -HUP $KILLPIDS
+               exit $RC
+       fi
+done
+
+for uri in $CONS_URI; do
+       echo "Adding database configuration on $uri"
+       $LDAPADD -D cn=config -H $uri -y $CONFIGPWF <<EOF > $TESTOUT 2>&1
+dn: olcDatabase={1}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+objectClass: olc${BACKEND}Config
+olcDatabase: {1}$BACKEND
+${nullExclude}olcDbDirectory: ./db
+$olcDbCheckpoint: 1024 5
+olcSuffix: $BASEDN
+olcRootDN: $MANAGERDN
+olcRootPW: $PASSWD
+olcSyncRepl: rid=1 provider=$FWD1_URI searchbase="$BASEDN"
+  binddn="$MANAGERDN" bindmethod=simple credentials=$PASSWD
+  type=refreshAndPersist retry="$RETRY" timeout=1
+
+EOF
+       RC=$?
+       if test $RC != 0 ; then
+               echo "ldapadd failed ($RC)!"
+               test $KILLSERVERS != no && kill -HUP $KILLPIDS
+               exit $RC
+       fi
+done
+
+for uri in $FWD1_URI $CONS_URI; do
+       echo "Using ldapsearch to check that $uri received database..."
+       for i in 1 2 3 4 5; do
+               $LDAPSEARCH -s base -b "$BASEDN" -H $uri \
+                       'objectclass=*' > /dev/null 2>&1
+               RC=$?
+               test $RC = 0 && break
+               echo "Waiting $i seconds for slapd to receive database..."
+               sleep $i
+       done
+       if test $RC != 0 ; then
+               echo "ldapsearch failed ($RC)!"
+               test $KILLSERVERS != no && kill -HUP $KILLPIDS
+               exit $RC
+       fi
+done
+
+RACE_NUM=0
+ERROR=0
+
+nEntries=10
+
+addEnd=1
+delEnd=1
+
+addIdx=1
+delIdx=1
+
+while test $ERROR -eq 0 -a $RACE_NUM -lt $INITIATION_RACE_TESTS ; do
+       RACE_NUM=`expr $RACE_NUM + 1`
+       echo "Running $RACE_NUM of $INITIATION_RACE_TESTS syncrepl initiation race tests..."
+
+       echo "Stopping forwarders for add test"
+       for pid in $FWD1_PID; do
+               kill -HUP $pid
+               wait $pid
+               KILLPIDS=`echo "$KILLPIDS " | sed -e "s/ $pid / /"`;
+       done
+
+       addStart=$addEnd
+       addEnd=`expr $addEnd + $nEntries`
+
+       echo "Using ldapadd to add $nEntries entries on provider"
+       while test $addIdx -lt $addEnd; do
+               $LDAPADD -D "$MANAGERDN" -H $PROV_URI -w $PASSWD <<EOF >> $TESTOUT 2>&1
+dn: ou=$addIdx,$BASEDN
+objectClass: top
+objectClass: organizationalUnit
+ou: $addIdx
+
+EOF
+               RC=$?
+               if test $RC != 0 ; then
+                       echo "ldapadd failed for entry $addIdx ($RC)!"
+                       test $KILLSERVERS != no && kill -HUP $KILLPIDS
+                       exit $RC
+               fi
+               addIdx=`expr $addIdx + 1`
+       done
+
+       echo "Starting forwarders again"
+       cd $FWD1_DIR
+       $SLAPD -F slapd.d -h $FWD1_URI -d $LVL $TIMING >> $FWD1_LOG 2>&1 &
+       FWD1_PID=$!
+       KILLPIDS="$KILLPIDS $FWD1_PID"
+       cd $TESTWD
+
+       addEnd=`expr $addEnd + $nEntries`
+
+       echo "Using ldapadd to add $nEntries more entries on provider"
+       while test $addIdx -lt $addEnd; do
+               $LDAPADD -D "$MANAGERDN" -H $PROV_URI -w $PASSWD <<EOF >> $TESTOUT 2>&1
+dn: ou=$addIdx,$BASEDN
+objectClass: top
+objectClass: organizationalUnit
+ou: $addIdx
+
+EOF
+               RC=$?
+               if test $RC != 0 ; then
+                       echo "ldapadd failed for entry $addIdx ($RC)!"
+                       test $KILLSERVERS != no && kill -HUP $KILLPIDS
+                       exit $RC
+               fi
+               addIdx=`expr $addIdx + 1`
+       done
+
+       for uri in $FWD1_URI $CONS_URI; do
+               echo "Checking replication to $uri"
+               RC=32
+               i=$addStart
+               while test $i -lt $addEnd; do
+                       for j in 1 2 3 4 5; do
+                               RESULT=`$LDAPSEARCH -H $uri -s base -b "ou=$i,$BASEDN" 2>&1 \
+                                       | awk '/^dn:/ {print "OK"}'`
+                               if test "x$RESULT$nullOK" = "xOK" ; then
+                                       RC=0
+                                       break
+                               fi
+                               echo "Waiting $j seconds for $uri to receive entry $i..."
+                               sleep $j
+                       done
+                       if test $RC != 0 ; then
+                               echo "ERROR: Entry $i not replicated to $uri! ($RC)!"
+                               ERROR=1
+                               break
+                       fi
+                       i=`expr $i + 1`
+               done
+               if test $ERROR != 0; then break; fi
+       done
+       if test $ERROR != 0; then break; fi
+
+       echo "Stopping forwarders for add/delete test"
+       for pid in $FWD1_PID; do
+               kill -HUP $pid
+               wait $pid
+               KILLPIDS=`echo "$KILLPIDS " | sed -e "s/ $pid / /"`;
+       done
+
+       addStart=$addEnd
+       addEnd=`expr $addEnd + $nEntries`
+
+       echo "Using ldapadd to add $nEntries entries on provider"
+       while test $addIdx -lt $addEnd; do
+               $LDAPADD -D "$MANAGERDN" -H $PROV_URI -w $PASSWD <<EOF >> $TESTOUT 2>&1
+dn: ou=$addIdx,$BASEDN
+objectClass: top
+objectClass: organizationalUnit
+ou: $addIdx
+
+EOF
+               RC=$?
+               if test $RC != 0 ; then
+                       echo "ldapadd failed for entry $addIdx ($RC)!"
+                       test $KILLSERVERS != no && kill -HUP $KILLPIDS
+                       exit $RC
+               fi
+               addIdx=`expr $addIdx + 1`
+       done
+
+       delStart=$delEnd
+       delEnd=`expr $delEnd + $nEntries`
+
+       echo "Using ldapdelete to delete $nEntries entries on provider"
+       while test $delIdx -lt $delEnd; do
+               $LDAPDELETE -D "$MANAGERDN" -H $PROV_URI -w $PASSWD "ou=$delIdx,$BASEDN"
+               RC=$?
+               if test $RC != 0 ; then
+                       echo "ldapdelete failed ($RC)!"
+                       test $KILLSERVERS != no && kill -HUP $KILLPIDS
+                       exit 1
+               fi
+               delIdx=`expr $delIdx + 1`
+       done
+
+       echo "Starting forwarders again"
+       cd $FWD1_DIR
+       $SLAPD -F slapd.d -h $FWD1_URI -d $LVL $TIMING >> $FWD1_LOG 2>&1 &
+       FWD1_PID=$!
+       KILLPIDS="$KILLPIDS $FWD1_PID"
+       cd $TESTWD
+
+       addEnd=`expr $addEnd + $nEntries`
+       delEnd=`expr $delEnd + $nEntries`
+
+       echo "Using ldapadd to add $nEntries more entries on provider"
+       while test $addIdx -lt $addEnd; do
+               $LDAPADD -D "$MANAGERDN" -H $PROV_URI -w $PASSWD <<EOF >> $TESTOUT 2>&1
+dn: ou=$addIdx,$BASEDN
+objectClass: top
+objectClass: organizationalUnit
+ou: $addIdx
+
+EOF
+               RC=$?
+               if test $RC != 0 ; then
+                       echo "ldapadd failed for entry $addIdx ($RC)!"
+                       test $KILLSERVERS != no && kill -HUP $KILLPIDS
+                       exit $RC
+               fi
+               addIdx=`expr $addIdx + 1`
+       done
+
+       echo "Using ldapdelete to delete $nEntries more entries on provider"
+       while test $delIdx -lt $delEnd; do
+               $LDAPDELETE -D "$MANAGERDN" -H $PROV_URI -w $PASSWD "ou=$delIdx,$BASEDN"
+               RC=$?
+               if test $RC != 0 ; then
+                       echo "ldapdelete failed ($RC)!"
+                       test $KILLSERVERS != no && kill -HUP $KILLPIDS
+                       exit 1
+               fi
+               delIdx=`expr $delIdx + 1`
+       done
+
+       for uri in $FWD1_URI $CONS_URI; do
+               echo "Checking replication to $uri"
+               RC=32
+               i=$addStart
+               while test $i -lt $addEnd; do
+                       for j in 1 2 3 4 5; do
+                               RESULT=`$LDAPSEARCH -H $uri -s base -b "ou=$i,$BASEDN" 2>&1 \
+                                       | awk '/^dn:/ {print "OK"}'`
+                               if test "x$RESULT$nullOK" = "xOK" ; then
+                                       RC=0
+                                       break
+                               fi
+                               echo "Waiting $j seconds for $uri to receive entry $i..."
+                               sleep $j
+                       done
+                       if test $RC != 0 ; then
+                               echo "ERROR: Entry $i not replicated to $uri! ($RC)!"
+                               ERROR=1
+                               break
+                       fi
+                       i=`expr $i + 1`
+               done
+               if test $ERROR != 0; then break; fi
+
+               i=$delStart
+               while test $i -lt $delEnd; do
+                       for j in 1 2 3 4 5; do
+                               $LDAPSEARCH -s base -b "ou=$i,$BASEDN" -H $uri > /dev/null 2>&1
+                               RC=$?
+                               if test $RC = $noObj; then break; fi
+                               echo "Waiting $j seconds for $uri to delete entry $i..."
+                               sleep $j
+                       done
+                       if test $RC != $noObj; then
+                               echo "ERROR: Entry $i not removed on $uri! (RC=$RC)"
+                               ERROR=1
+                               break
+                       fi
+                       i=`expr $i + 1`
+               done    
+               if test $ERROR != 0; then break; fi
+       done
+       if test $ERROR != 0; then break; fi
+
+       echo "Stopping forwarders for delete test"
+       for pid in $FWD1_PID; do
+               kill -HUP $pid
+               wait $pid
+               KILLPIDS=`echo "$KILLPIDS " | sed -e "s/ $pid / /"`;
+       done
+
+       delStart=$delEnd
+       delEnd=`expr $delEnd + $nEntries`
+
+       echo "Using ldapdelete to delete entries on provider"
+       while test $delIdx -lt $delEnd; do
+               $LDAPDELETE -D "$MANAGERDN" -H $PROV_URI -w $PASSWD "ou=$delIdx,$BASEDN"
+               RC=$?
+               if test $RC != 0 ; then
+                       echo "ldapdelete failed ($RC)!"
+                       test $KILLSERVERS != no && kill -HUP $KILLPIDS
+                       exit 1
+               fi
+               delIdx=`expr $delIdx + 1`
+       done
+
+       echo "Starting forwarders again"
+       cd $FWD1_DIR
+       $SLAPD -F slapd.d -h $FWD1_URI -d $LVL $TIMING >> $FWD1_LOG 2>&1 &
+       FWD1_PID=$!
+       KILLPIDS="$KILLPIDS $FWD1_PID"
+       cd $TESTWD
+
+       delEnd=`expr $delEnd + $nEntries`
+
+       echo "Using ldapdelete to delete $nEntries more entries on provider"
+       while test $delIdx -lt $delEnd; do
+               $LDAPDELETE -D "$MANAGERDN" -H $PROV_URI -w $PASSWD "ou=$delIdx,$BASEDN"
+               RC=$?
+               if test $RC != 0 ; then
+                       echo "ldapdelete failed ($RC)!"
+                       test $KILLSERVERS != no && kill -HUP $KILLPIDS
+                       exit 1
+               fi
+               delIdx=`expr $delIdx + 1`
+       done
+
+       for uri in $FWD1_URI $CONS_URI; do
+               echo "Checking replication to $uri"
+               RC=0
+               i=$delStart
+               while test $i -lt $delEnd; do
+                       for j in 1 2 3 4 5; do
+                               $LDAPSEARCH -s base -b "ou=$i,$BASEDN" -H $uri > /dev/null 2>&1
+                               RC=$?
+                               if test $RC = $noObj; then break; fi
+                               echo "Waiting $j seconds for $uri to delete entry $i..."
+                               sleep $j
+                       done
+                       if test $RC != $noObj; then
+                               echo "ERROR: Entry $i not removed on $uri! (RC=$RC)"
+                               ERROR=1
+                               break
+                       fi
+                       i=`expr $i + 1`
+               done    
+               if test $ERROR != 0; then break; fi
+       done
+       if test $ERROR != 0; then break; fi
+
+       echo "Checking contextCSN"
+       CSN_ERRORS=0
+       CSN1=`$LDAPSEARCH -H $URI1 -b $BASEDN -s base contextCSN | grep contextCSN`
+       CSN2=`$LDAPSEARCH -H $URI2 -b $BASEDN -s base contextCSN | grep contextCSN`
+       CSN3=`$LDAPSEARCH -H $URI3 -b $BASEDN -s base contextCSN | grep contextCSN`
+
+       if test -z "$CSN1" ; then
+               test $BACKEND = null && break
+               echo "ERROR: contextCSN empty on provider"
+               ERROR=1
+               break
+       fi
+       nCSN=`echo "$CSN1" | wc -l`
+       if test "$nCSN" -ne 1 ; then
+               echo "ERROR: Wrong contextCSN count on provder, should be 1"
+               echo "$CSN1"
+               test $KILLSERVERS != no && kill -HUP $KILLPIDS
+               exit 1
+       fi
+       if  test -z "$CSN2" -o "$CSN1" != "$CSN2" ; then
+               echo "ERROR: contextCSN mismatch between provider and consumer"
+               echo "contextCSN on provider: $CSN1"
+               echo "contextCSN on consumer: $CSN2"
+               ERROR=1
+               break
+       fi
+       if  test -z "$CSN3" -o "$CSN1" != "$CSN3" ; then
+               echo "ERROR: contextCSN mismatch between provider and forward1"
+               echo "contextCSN on provider: $CSN1"
+               echo "contextCSN on forward1: $CSN3"
+               ERROR=1
+               break
+       fi
+done
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+if test $ERROR != 0; then
+       echo "Error found after $RACE_NUM of $INITIATION_RACE_TESTS iterations"
+       exit 1
+else
+       echo "No race errors found after $INITIATION_RACE_TESTS iterations"
+fi
+
+echo ">>>>> Test succeeded"
+
+exit 0