ITS#6625 concurrency patch from Doug Leavitt @ Oracle .com

This commit is contained in:
Howard Chu 2010-10-22 21:45:48 +00:00
parent 026713f497
commit 0f30db1c46
19 changed files with 2499 additions and 249 deletions

View File

@ -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]

126
doc/man/man3/ldap_dup.3 Normal file
View File

@ -0,0 +1,126 @@
.TH LDAP_OPEN 3 "RELEASEDATE" "OpenLDAP LDVERSION"
.\" $OpenLDAP$
.\" Copyright 1998-2010 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

View File

@ -0,0 +1 @@
ldap_destroy.3

View 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.

View 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 */

View 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 LDO_MUTEX_NULL
#define LDO_MUTEX_NULL ,PTHREAD_MUTEX_INITIALIZER
#define MUTEX_FIRSTCREATE(m)
#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 LDO_MUTEX_NULL
#define LDO_MUTEX_NULL ,MUTEX_INITIALIZER
#define MUTEX_FIRSTCREATE(m)
#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 LDO_MUTEX_NULL
#define LDO_MUTEX_NULL ,PTH_MUTEX_INIT
#define MUTEX_FIRSTCREATE(m)
#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 LDO_MUTEX_NULL
#define LDO_MUTEX_NULL ,DEFAULTMUTEX
#define MUTEX_FIRSTCREATE(m)
#endif
#elif defined(HAVE_NT_THREADS)
/*************************************
@ -162,6 +180,11 @@ typedef HANDLE ldap_int_thread_mutex_t;
typedef HANDLE ldap_int_thread_cond_t;
typedef DWORD ldap_int_thread_key_t;
#ifndef LDO_MUTEX_NULL
#define LDO_MUTEX_NULL ,(HANDLE)0
#define MUTEX_FIRSTCREATE(m) (!m ? 0 : ldap_pvt_thread_mutex_init(&m) )
#endif
LDAP_END_DECL
#else
@ -186,6 +209,11 @@ typedef int ldap_int_thread_key_t;
#define LDAP_THREAD_HAVE_TPOOL 1
typedef int ldap_int_thread_pool_t;
#ifndef LDO_MUTEX_NULL
#define LDO_MUTEX_NULL
#define MUTEX_FIRSTCREATE(m)
#endif
LDAP_END_DECL
#endif /* no threads support */

View 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
{
@ -287,10 +290,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 +304,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 );
}

View 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;

View File

@ -36,7 +36,7 @@
#include "lutil.h"
struct ldapoptions ldap_int_global_options =
{ LDAP_UNINITIALIZED, LDAP_DEBUG_NONE };
{ LDAP_UNINITIALIZED, LDAP_DEBUG_NONE LDO_MUTEX_NULL };
#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 )
{
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;
}

View 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,12 @@ 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;
#else
#define LDO_MUTEX_NULL
#define MUTEX_FIRSTCREATE(m)
#endif
#ifdef LDAP_CONNECTIONLESS
#define LDAP_IS_UDP(ld) ((ld)->ld_options.ldo_is_udp)
void* ldo_peer; /* struct sockaddr* */
@ -361,24 +368,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 +400,79 @@ struct ldap {
#define ld_urllist_params ld_options.ldo_urllist_params
#define ld_version ld_options.ldo_version
unsigned short ld_lberoptions;
ber_int_t ld_errno;
char *ld_error;
char *ld_matched;
char **ld_referrals;
ber_len_t ld_msgid;
/* do not mess with these */
LDAPRequest *ld_requests; /* list of outstanding requests */
LDAPMessage *ld_responses; /* list of outstanding 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;
#define ld_ldopts_mutex ld_options.ldo_mutex
#endif
ber_len_t ld_nabandoned;
ber_int_t *ld_abandoned; /* array of abandoned requests */
unsigned short ldc_lberoptions;
#define ld_lberoptions ldc->ldc_lberoptions
LDAPCache *ld_cache; /* non-null if cache is initialized */
/* protected by msgid_mutex */
ber_len_t ldc_msgid;
#define ld_msgid ldc->ldc_msgid
/* do not mess with these */
/* 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 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
/* 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
/* 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 )
@ -448,9 +501,9 @@ LDAP_V( ldap_pvt_thread_mutex_t ) ldap_int_gssapi_mutex;
#ifdef LDAP_R_COMPILE
#define LDAP_NEXT_MSGID(ld, id) \
LDAP_MUTEX_LOCK( &(ld)->ld_req_mutex ); \
LDAP_MUTEX_LOCK( &(ld)->ld_msgid_mutex ); \
id = ++(ld)->ld_msgid; \
LDAP_MUTEX_UNLOCK( &(ld)->ld_req_mutex )
LDAP_MUTEX_UNLOCK( &(ld)->ld_msgid_mutex )
#else
#define LDAP_NEXT_MSGID(ld, id) id = ++(ld)->ld_msgid
#endif
@ -584,8 +637,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 );

View File

@ -35,11 +35,11 @@
#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 );
}

View 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

View File

@ -53,6 +53,29 @@
#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 );
}

View 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 );
@ -535,7 +530,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 ) {
@ -548,7 +543,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;
}
@ -1337,35 +1332,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;
}

View 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,

View File

@ -14,17 +14,21 @@
## <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)

758
tests/progs/slapd-mtread.c Normal file
View File

@ -0,0 +1,758 @@
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 1999-2009 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 perfrom 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];
/*
* 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 };
ldap_pvt_thread_t rtid[MAX_THREAD], rwtid[MAX_THREAD];
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, (void*)i);
snprintf(outstr, BUFSIZ, "Created RO thread %d [%d]", i, 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, (void*)i);
snprintf(outstr, BUFSIZ, "Created RW thread %d [%d]", i, 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 = (int)arg;
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 = (int)arg;
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)
free( 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 %x cnt: %d (retried %d) (%s)", \
whoami(), 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;
}
}
}

View File

@ -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

289
tests/scripts/test060-mt-hot Executable file
View File

@ -0,0 +1,289 @@
#! /bin/sh
# $OpenLDAP$
## This work is part of OpenLDAP Software <http://www.openldap.org/>.
##
## Copyright 1998-2009 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>.
echo "running defines.sh"
. $SRCDIR/scripts/defines.sh
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 $LOCALHOST -p $PORT1 \
'(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 $LOCALHOST -p $PORT1 -D "$MANAGERDN" -w $PASSWD \
-e "$MONITORDN" \
-m $THR -L $OUTER -l $INNER
$SLAPDMTREAD -h $LOCALHOST -p $PORT1 -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 $LOCALHOST -p $PORT1 -D "$MANAGERDN" -w $PASSWD \
-e "$MONITORDN" \
-m $THR -L $OUTER -l $INNER
$SLAPDMTREAD -h $LOCALHOST -p $PORT1 -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 $LOCALHOST -p $PORT1 -D "$MANAGERDN" -w $PASSWD \
-e "$MONITORDN" \
-m $THR -L $OUTER -l $INNER
$SLAPDMTREAD -h $LOCALHOST -p $PORT1 -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 $LOCALHOST -p $PORT1 -D "$MANAGERDN" -w $PASSWD \
-e "$BASEDN" -f "(objectclass=*)" \
-m $THR -L $OUTER -l $INNER
$SLAPDMTREAD -h $LOCALHOST -p $PORT1 -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 $LOCALHOST -p $PORT1 -D "$MANAGERDN" -w $PASSWD \
-e "$BASEDN" -f "(objectclass=*)" \
-m $THR -L $OUTER -l $INNER
$SLAPDMTREAD -h $LOCALHOST -p $PORT1 -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 $LOCALHOST -p $PORT1 -D "$MANAGERDN" -w $PASSWD \
-e "$BASEDN" -f "(objectclass=*)" \
-m $THR -L $OUTER -l $INNER
$SLAPDMTREAD -h $LOCALHOST -p $PORT1 -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 $LOCALHOST -p $PORT1 -D "$MANAGERDN" -w $PASSWD \
-e "$MONITORDN" \
-c $CONN -m $THR -L $OUTER -l $INNER
$SLAPDMTREAD -h $LOCALHOST -p $PORT1 -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 $LOCALHOST -p $PORT1 -D "$MANAGERDN" -w $PASSWD \
-e "$MONITORDN" \
-c $CONN -m $THR -L $OUTER -l $INNER
$SLAPDMTREAD -h $LOCALHOST -p $PORT1 -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 $LOCALHOST -p $PORT1 -D "$MANAGERDN" -w $PASSWD \
-e "$BASEDN" -f "(objectclass=*)" \
-c $CONN -m $THR -L $OUTER -l $INNER
$SLAPDMTREAD -h $LOCALHOST -p $PORT1 -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 $LOCALHOST -p $PORT1 -D "$MANAGERDN" -w $PASSWD \
-e "$BASEDN" -f "(&(!(cn=rwtest*))(objectclass=*))" \
-c $CONN -m $THR -M $WTHR -L $OUTER -l $INNER
$SLAPDMTREAD -h $LOCALHOST -p $PORT1 -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 $LOCALHOST -p $PORT1 -D "$MANAGERDN" -w $PASSWD \
-e "$BASEDN" -f "(&(!(cn=rwtest*))(objectclass=*))" \
-c $CONN -m $THR -M $WTHR -L $OUTER -l $INNER
$SLAPDMTREAD -h $LOCALHOST -p $PORT1 -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