Commit 769083f8 authored by Quanah Gibson-Mount's avatar Quanah Gibson-Mount
Browse files

ITS#6625,ITS#5421

parent 58c0bf5a
......@@ -2,6 +2,7 @@ OpenLDAP 2.4 Change Log
OpenLDAP 2.4.24 Engineering
Added LDIF line wrapping setting (ITS#6645)
Added libldap concurrency support (ITS#6625,ITS#5421)
Added libldap MozNSS non-blocking support (ITS#6714)
Added libldap MozNSS cert centralization (ITS#6742)
Added libldap x500UniqueIdentifier handling (ITS#6741)
......
......@@ -64,7 +64,6 @@
#include "lutil_ldap.h"
#include "ldif.h"
#include "ldap_defaults.h"
#include "ldap_log.h"
#include "ldap_pvt.h"
#include "lber_pvt.h"
......
......@@ -66,7 +66,6 @@
#include "lutil.h"
#include "lutil_ldap.h"
#include "ldap_defaults.h"
#include "ldap_log.h"
#include "ldap_pvt.h"
#include "common.h"
......
This diff is collapsed.
.TH LDAP_OPEN 3 "RELEASEDATE" "OpenLDAP LDVERSION"
.\" $OpenLDAP$
.\" Copyright 1998-2011 The OpenLDAP Foundation All Rights Reserved.
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
.SH NAME
ldap_dup, ldap_destroy, \- Duplicate and destroy LDAP session handles
.SH LIBRARY
OpenLDAP LDAP (libldap, \-lldap)
.SH SYNOPSIS
.nf
.ft B
#include <ldap.h>
.LP
.ft B
LDAP *ldap_dup(
.RS
.ft B
LDAP *\fIold\fB );
.RE
.LP
.ft B
int ldap_destroy(
.RS
.ft B
LDAP *\fIold\fB );
.RE
.SH DESCRIPTION
.LP
.B ldap_dup()
duplicates an existing LDAP
.RB ( "LDAP *" )
session handle.
The new session handle may be used concurrently with the
original session handle.
In a threaded environment, different threads may execute concurrent
requests on the same connection/session without fear of contamination.
Each session handle manages its own private error results.
.LP
.B ldap_destroy()
destroys an existing session handle.
.LP
The
.B ldap_dup()
and
.B ldap_destroy()
functions are used in conjunction with a "thread safe" version
of
.B libldap
.RB ( libldap_r )
to enable operation thread safe API calls, so that a single session
may be simultaneously used across multiple threads with consistent
error handling.
.LP
When a session is created through the use of one of the session creation
functions including
.BR ldap_open (3),
.BR ldap_init (3),
.BR ldap_initialize (3)
or
.BR ldap_init_fd (3)
an
.B "LDAP *"
session handle is returned to the application.
The session handle may be shared amongst threads, however the
error codes are unique to a session handle.
Multiple threads performing different operations using the same
session handle will result in inconsistent error codes and
return values.
.LP
To prevent this confusion,
.B ldap_dup()
is used duplicate an existing session handle so that multiple threads
can share the session, and maintain consistent error information
and results.
.LP
The message queues for a session are shared between sibling session handles.
Results of operations on a sibling session handles are accessible
to all the sibling session handles.
Applications desiring results associated with a specific operation
should provide the appropriate msgid to
.BR ldap_result() .
Applications should avoid calling
.B ldap_result()
with
.B LDAP_RES_ANY
as that may "steal" and return results in the calling thread
that another operation in a different thread, using a
different session handle, may require to complete.
.LP
When
.B ldap_unbind()
is called on a session handle with siblings, all the
siblings become invalid.
.LP
Siblings must be destroyed using
.BR ldap_destroy() .
Session handle resources associated with the original
.RB ( "LDAP *" )
will be freed when the last session handle is destroyed or when
.B ldap_unbind()
is called, if no other session handles currently exist.
.SH ERRORS
If an error occurs,
.B ldap_dup()
will return NULL and
.I errno
should be set appropriately.
.B ldap_destroy()
will directly return the LDAP code associated to the error (or
.I LDAP_SUCCESS
in case of success);
.I errno
should be set as well whenever appropriate.
.SH SEE ALSO
.BR ldap_open (3),
.BR ldap_init (3),
.BR ldap_initialize (3),
.BR ldap_init_fd (3),
.BR errno (3)
.SH ACKNOWLEDGEMENTS
This work is based on the previously proposed
.B LDAP C API Concurrency Extensions
draft
.BR ( draft-zeilenga-ldap-c-api-concurrency-00.txt )
effort.
.so ../Project
......@@ -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.
......
......@@ -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 */
......
......@@ -69,6 +69,11 @@ typedef pthread_key_t ldap_int_thread_key_t;
typedef pthread_rwlock_t ldap_int_thread_rdwr_t;
#endif
#ifndef LDAP_INT_MUTEX_NULL
#define LDAP_INT_MUTEX_NULL PTHREAD_MUTEX_INITIALIZER
#define LDAP_INT_MUTEX_FIRSTCREATE(m) ((void) 0)
#endif
LDAP_END_DECL
#elif defined ( HAVE_MACH_CTHREADS )
......@@ -91,6 +96,11 @@ typedef struct mutex ldap_int_thread_mutex_t;
typedef struct condition ldap_int_thread_cond_t;
typedef cthread_key_t ldap_int_thread_key_t;
#ifndef LDAP_INT_MUTEX_NULL
#define LDAP_INT_MUTEX_NULL MUTEX_INITIALIZER
#define LDAP_INT_MUTEX_FIRSTCREATE(m) ((void) 0)
#endif
LDAP_END_DECL
#elif defined( HAVE_GNU_PTH )
......@@ -115,6 +125,11 @@ typedef pth_key_t ldap_int_thread_key_t;
typedef pth_rwlock_t ldap_int_thread_rdwr_t;
#endif
#ifndef LDAP_INT_MUTEX_NULL
#define LDAP_INT_MUTEX_NULL PTH_MUTEX_INIT
#define LDAP_INT_MUTEX_FIRSTCREATE(m) ((void) 0)
#endif
LDAP_END_DECL
#elif defined( HAVE_THR )
......@@ -143,7 +158,10 @@ typedef thread_key_t ldap_int_thread_key_t;
#define LDAP_THREAD_HAVE_SETCONCURRENCY 1
#endif
LDAP_END_DECL
#ifndef LDAP_INT_MUTEX_NULL
#define LDAP_INT_MUTEX_NULL DEFAULTMUTEX
#define LDAP_INT_MUTEX_FIRSTCREATE(m) ((void) 0)
#endif
#elif defined(HAVE_NT_THREADS)
/*************************************
......@@ -162,6 +180,12 @@ typedef HANDLE ldap_int_thread_mutex_t;
typedef HANDLE ldap_int_thread_cond_t;
typedef DWORD ldap_int_thread_key_t;
#ifndef LDAP_INT_MUTEX_NULL
#define LDAP_INT_MUTEX_NULL ((HANDLE)0)
#define LDAP_INT_MUTEX_FIRSTCREATE(m) \
((void) ((m) || ldap_int_thread_mutex_init(&(m))))
#endif
LDAP_END_DECL
#else
......@@ -186,6 +210,11 @@ typedef int ldap_int_thread_key_t;
#define LDAP_THREAD_HAVE_TPOOL 1
typedef int ldap_int_thread_pool_t;
#ifndef LDAP_INT_MUTEX_NULL
#define LDAP_INT_MUTEX_NULL 0
#define LDAP_INT_MUTEX_FIRSTCREATE(m) ((void) 0)
#endif
LDAP_END_DECL
#endif /* no threads support */
......@@ -256,6 +285,10 @@ typedef struct {
ldap_int_thread_t owner;
} ldap_debug_thread_mutex_t;
#define LDAP_DEBUG_MUTEX_NULL {LDAP_INT_MUTEX_NULL, {0,0,{0},0} /*,owner*/}
#define LDAP_DEBUG_MUTEX_FIRSTCREATE(m) \
((void) ((m).usage.state || ldap_pvt_thread_mutex_init(&(m))))
typedef struct {
ldap_int_thread_cond_t wrapped;
ldap_debug_usage_info_t usage;
......
......@@ -28,10 +28,14 @@ typedef ldap_int_thread_t ldap_pvt_thread_t;
typedef ldap_debug_thread_mutex_t ldap_pvt_thread_mutex_t;
typedef ldap_debug_thread_cond_t ldap_pvt_thread_cond_t;
typedef ldap_debug_thread_rdwr_t ldap_pvt_thread_rdwr_t;
#define LDAP_PVT_MUTEX_FIRSTCREATE LDAP_DEBUG_MUTEX_FIRSTCREATE
#define LDAP_PVT_MUTEX_NULL LDAP_DEBUG_MUTEX_NULL
#else
typedef ldap_int_thread_mutex_t ldap_pvt_thread_mutex_t;
typedef ldap_int_thread_cond_t ldap_pvt_thread_cond_t;
typedef ldap_int_thread_rdwr_t ldap_pvt_thread_rdwr_t;
#define LDAP_PVT_MUTEX_FIRSTCREATE LDAP_INT_MUTEX_FIRSTCREATE
#define LDAP_PVT_MUTEX_NULL LDAP_INT_MUTEX_NULL
#endif
typedef ldap_int_thread_rmutex_t ldap_pvt_thread_rmutex_t;
typedef ldap_int_thread_key_t ldap_pvt_thread_key_t;
......
......@@ -206,7 +206,7 @@ start_again:;
* LDAP_NEXT_MSGID(ld, i);
*/
i = ++(ld)->ld_msgid;
LDAP_NEXT_MSGID(ld, i);
#ifdef LDAP_CONNECTIONLESS
if ( LDAP_IS_UDP(ld) ) {
struct sockaddr sa = {0};
......@@ -216,11 +216,14 @@ start_again:;
if ( LDAP_IS_UDP(ld) && ld->ld_options.ldo_version ==
LDAP_VERSION2 )
{
char *dn = ld->ld_options.ldo_cldapdn;
char *dn;
LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex );
dn = ld->ld_options.ldo_cldapdn;
if (!dn) dn = "";
err = ber_printf( ber, "{isti", /* '}' */
i, dn,
LDAP_REQ_ABANDON, msgid );
LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex );
} else
#endif
{
......@@ -276,7 +279,9 @@ start_again:;
if ( lr != NULL ) {
if ( sendabandon || lr->lr_status == LDAP_REQST_WRITING ) {
LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
ldap_free_connection( ld, lr->lr_conn, 0, 1 );
LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
}
if ( origid == msgid ) {
......@@ -287,10 +292,7 @@ start_again:;
}
}
/* ld_abandoned is actually protected by the ld_res_mutex;
* give up the ld_req_mutex and get the other */
LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
LDAP_MUTEX_LOCK( &ld->ld_res_mutex );
LDAP_MUTEX_LOCK( &ld->ld_abandon_mutex );
/* use bisection */
i = 0;
......@@ -304,8 +306,7 @@ start_again:;
ld->ld_errno = LDAP_SUCCESS;
}
LDAP_MUTEX_UNLOCK( &ld->ld_res_mutex );
LDAP_MUTEX_LOCK( &ld->ld_req_mutex );
LDAP_MUTEX_UNLOCK( &ld->ld_abandon_mutex );
return( ld->ld_errno );
}
......@@ -446,4 +447,3 @@ ldap_int_bisect_delete( ber_int_t **vp, ber_len_t *np, int id, int idx )
return 0;
}
......@@ -416,7 +416,7 @@ ldap_int_sasl_bind(
void *ssl;
rc = 0;
LDAP_MUTEX_LOCK( &ld->ld_req_mutex );
LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, &sd );
if ( sd == AC_SOCKET_INVALID ) {
......@@ -434,7 +434,7 @@ ldap_int_sasl_bind(
}
}
}
LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
if( rc != 0 ) return ld->ld_errno;
oldctx = ld->ld_defconn->lconn_sasl_authctx;
......@@ -1205,7 +1205,10 @@ ldap_int_sasl_bind(
LDAPControl **cctrls,
unsigned flags,
LDAP_SASL_INTERACT_PROC *interact,
void * defaults )
void *defaults,
LDAPMessage *result,
const char **rmech,
int *msgid )
{ return LDAP_NOT_SUPPORTED; }
int
......
......@@ -664,9 +664,7 @@ ldap_int_gss_spnego_bind_s( LDAP *ld )
gss_buffer_desc input_token, output_token = GSS_C_EMPTY_BUFFER;
struct berval cred, *scred = NULL;
#ifdef LDAP_R_COMPILE
ldap_pvt_thread_mutex_lock( &ldap_int_gssapi_mutex );
#endif
LDAP_MUTEX_LOCK( &ldap_int_gssapi_mutex );
/* get information from RootDSE entry */
rc = ldap_gssapi_get_rootdse_infos ( ld, &mechlist,
......@@ -784,9 +782,7 @@ gss_error:
(ret_mech != GSS_C_NO_OID ? ret_mech : req_mech ),
gss_rc, minor_status );
rc_error:
#ifdef LDAP_R_COMPILE
ldap_pvt_thread_mutex_unlock( &ldap_int_gssapi_mutex );
#endif
LDAP_MUTEX_UNLOCK( &ldap_int_gssapi_mutex );
LDAP_FREE( mechlist );
LDAP_FREE( ldapServiceName );
LDAP_FREE( dnsHostName );
......
......@@ -36,7 +36,7 @@
#include "lutil.h"
struct ldapoptions ldap_int_global_options =
{ LDAP_UNINITIALIZED, LDAP_DEBUG_NONE };
{ LDAP_UNINITIALIZED, LDAP_DEBUG_NONE LDAP_LDO_MUTEX_NULLARG };
#define ATTR_NONE 0
#define ATTR_BOOL 1
......@@ -510,6 +510,13 @@ ldap_int_destroy_global_options(void)
*/
void ldap_int_initialize_global_options( struct ldapoptions *gopts, int *dbglvl )
{
LDAP_PVT_MUTEX_FIRSTCREATE(gopts->ldo_mutex);
LDAP_MUTEX_LOCK( &gopts->ldo_mutex );
if (gopts->ldo_valid == LDAP_INITIALIZED) {
/* someone else got here first */
LDAP_MUTEX_UNLOCK( &gopts->ldo_mutex );
return;
}
if (dbglvl)
gopts->ldo_debug = *dbglvl;
else
......@@ -573,6 +580,7 @@ void ldap_int_initialize_global_options( struct ldapoptions *gopts, int *dbglvl
gopts->ldo_keepalive_idle = 0;
gopts->ldo_valid = LDAP_INITIALIZED;
LDAP_MUTEX_UNLOCK( &gopts->ldo_mutex );
return;
}
......
......@@ -174,6 +174,7 @@ typedef struct ldaplist {
/*
* structure representing get/set'able options
* which have global defaults.
* Protect access to this struct with ldo_mutex
*/
struct ldapoptions {
short ldo_valid;
......@@ -182,6 +183,15 @@ struct ldapoptions {
#define LDAP_VALID_SESSION 0x2
#define LDAP_TRASHED_SESSION 0xFF
int ldo_debug;
#ifdef LDAP_R_COMPILE
ldap_pvt_thread_mutex_t ldo_mutex;
#define LDAP_LDO_MUTEX_NULLARG , LDAP_PVT_MUTEX_NULL
#else
#define LDAP_LDO_MUTEX_NULLARG
#define LDAP_PVT_MUTEX_FIRSTCREATE(m) ((void) 0)
#endif
#ifdef LDAP_CONNECTIONLESS
#define LDAP_IS_UDP(ld) ((ld)->ld_options.ldo_is_udp)
void* ldo_peer; /* struct sockaddr* */
......@@ -361,24 +371,27 @@ typedef struct ldapreqinfo {
* structure representing an ldap connection
*/
struct ldap {
Sockbuf *ld_sb; /* socket descriptor & buffer */
struct ldap_common {
Sockbuf *ldc_sb; /* socket descriptor & buffer */
#define ld_sb ldc->ldc_sb
struct ldapoptions ld_options;
/* protected by ldo_mutex */
struct ldapoptions ldc_options;
#define ld_options ldc->ldc_options
#define ld_valid ld_options.ldo_valid
#define ld_debug ld_options.ldo_debug
#define ld_deref ld_options.ldo_deref
#define ld_timelimit ld_options.ldo_timelimit
#define ld_sizelimit ld_options.ldo_sizelimit
#define ld_timelimit ld_options.ldo_timelimit
#define ld_sizelimit ld_options.ldo_sizelimit
#define ld_defbinddn ld_options.ldo_defbinddn
#define ld_defbinddn ld_options.ldo_defbinddn
#define ld_defbase ld_options.ldo_defbase
#define ld_defhost ld_options.ldo_defhost
#define ld_defport ld_options.ldo_defport
#define ld_refhoplimit ld_options.ldo_refhoplimit
#define ld_refhoplimit ld_options.ldo_refhoplimit
#define ld_sctrls ld_options.ldo_sctrls
#define ld_cctrls ld_options.ldo_cctrls
......@@ -390,36 +403,79 @@ struct ldap {
#define ld_urllist_params ld_options.ldo_urllist_params
#define ld_version ld_options.ldo_version
#ifdef LDAP_R_COMPILE
#define ld_ldopts_mutex ld_options.ldo_mutex
#endif
unsigned short ld_lberoptions;
unsigned short ldc_lberoptions;
#define ld_lberoptions ldc->ldc_lberoptions
ber_int_t ld_errno;
char *ld_error;
char *ld_matched;
char **ld_referrals;
ber_len_t ld_msgid;
/* protected by msgid_mutex */
ber_len_t ldc_msgid;
#define ld_msgid ldc->ldc_msgid
/* do not mess with these */
LDAPRequest *ld_requests; /* list of outstanding requests */
LDAPMessage *ld_responses; /* list of outstanding responses */
/* protected by req_mutex */
LDAPRequest *ldc_requests; /* list of outstanding requests */
/* protected by res_mutex */
LDAPMessage *ldc_responses; /* list of outstanding responses */
#define ld_requests ldc->ldc_requests
#define ld_responses ldc->ldc_responses
#ifdef LDAP_R_COMPILE
ldap_pvt_thread_mutex_t ld_conn_mutex;
ldap_pvt_thread_mutex_t ld_req_mutex;
ldap_pvt_thread_mutex_t ld_res_mutex;
ldap_pvt_thread_mutex_t ldc_msgid_mutex;
ldap_pvt_thread_mutex_t ldc_conn_mutex;
ldap_pvt_thread_mutex_t ldc_req_mutex;
ldap_pvt_thread_mutex_t ldc_res_mutex;
ldap_pvt_thread_mutex_t ldc_abandon_mutex;
#define ld_msgid_mutex ldc->ldc_msgid_mutex
#define ld_conn_mutex ldc->ldc_conn_mutex
#define ld_req_mutex ldc->ldc_req_mutex
#define ld_res_mutex ldc->ldc_res_mutex
#define ld_abandon_mutex ldc->ldc_abandon_mutex
#endif
ber_len_t ld_nabandoned;
ber_int_t *ld_abandoned; /* array of abandoned requests */
/* protected by abandon_mutex */
ber_len_t ldc_nabandoned;
ber_int_t *ldc_abandoned; /* array of abandoned requests */
#define ld_nabandoned ldc->ldc_nabandoned
#define ld_abandoned ldc->ldc_abandoned
LDAPCache *ld_cache; /* non-null if cache is initialized */
/* unused by libldap */
LDAPCache *ldc_cache; /* non-null if cache is initialized */
#define ld_cache ldc->ldc_cache
/* do not mess with the rest though */
LDAPConn *ld_defconn; /* default connection */
LDAPConn *ld_conns; /* list of server connections */
void *ld_selectinfo; /* platform specifics for select */
/* protected by conn_mutex */
LDAPConn *ldc_defconn; /* default connection */
#define ld_defconn ldc->ldc_defconn
LDAPConn *ldc_conns; /* list of server connections */
#define ld_conns ldc->ldc_conns
void *ldc_selectinfo;/* platform specifics for select */
#define ld_selectinfo ldc->ldc_selectinfo
/* ldap_common refcnt - free only if 0 */
#ifdef LDAP_R_COMPILE
ldap_pvt_thread_mutex_t ldc_mutex;
#define ld_ldcmutex ldc->ldc_mutex
#endif
/* protected by ldc_mutex */
unsigned int ldc_refcnt;
#define ld_ldcrefcnt ldc->ldc_refcnt
};
struct ldap {
/* thread shared */
struct ldap_common *ldc;
/* thread specific */
ber_int_t ld_errno;
char *ld_error;
char *ld_matched;
char **ld_referrals;
};
#define LDAP_VALID(ld) ( (ld)->ld_valid == LDAP_VALID_SESSION )
#define LDAP_TRASHED(ld) ( (ld)->ld_valid == LDAP_TRASHED_SESSION )
#define LDAP_TRASH(ld) ( (ld)->ld_valid = LDAP_TRASHED_SESSION )
......@@ -441,19 +497,16 @@ LDAP_V( ldap_pvt_thread_mutex_t ) ldap_int_gssapi_mutex;
#define LDAP_ASSERT_MUTEX_OWNER(mutex) \
LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER(mutex)
#else
#define LDAP_MUTEX_LOCK(mutex)
#define LDAP_MUTEX_UNLOCK(mutex)
#define LDAP_ASSERT_MUTEX_OWNER(mutex)
#define LDAP_MUTEX_LOCK(mutex) ((void) 0)
#define LDAP_MUTEX_UNLOCK(mutex) ((void) 0)
#define LDAP_ASSERT_MUTEX_OWNER(mutex) ((void) 0)
#endif
#ifdef LDAP_R_COMPILE
#define LDAP_NEXT_MSGID(ld, id) \
LDAP_MUTEX_LOCK( &(ld)->ld_req_mutex ); \
id = ++(ld)->ld_msgid; \
LDAP_MUTEX_UNLOCK( &(ld)->ld_req_mutex )
#else
#define LDAP_NEXT_MSGID(ld, id) id = ++(ld)->ld_msgid
#endif
#define LDAP_NEXT_MSGID(ld, id) do { \
LDAP_MUTEX_LOCK( &(ld)->ld_msgid_mutex ); \
(id) = ++(ld)->ld_msgid; \
LDAP_MUTEX_UNLOCK( &(ld)->ld_msgid_mutex ); \
} while (0)
/*
* in abandon.c
......@@ -592,8 +645,11 @@ LDAP_F (ber_int_t) ldap_send_initial_request( LDAP *ld, ber_tag_t msgtype,
LDAP_F (BerElement *) ldap_alloc_ber_with_options( LDAP *ld );
LDAP_F (void) ldap_set_ber_options( LDAP *ld, BerElement *ber );