1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
3*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
4*7c478bd9Sstevel@tonic-gate  */
5*7c478bd9Sstevel@tonic-gate 
6*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
7*7c478bd9Sstevel@tonic-gate 
8*7c478bd9Sstevel@tonic-gate 
9*7c478bd9Sstevel@tonic-gate /*
10*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the Netscape Public
11*7c478bd9Sstevel@tonic-gate  * License Version 1.1 (the "License"); you may not use this file
12*7c478bd9Sstevel@tonic-gate  * except in compliance with the License. You may obtain a copy of
13*7c478bd9Sstevel@tonic-gate  * the License at http://www.mozilla.org/NPL/
14*7c478bd9Sstevel@tonic-gate  *
15*7c478bd9Sstevel@tonic-gate  * Software distributed under the License is distributed on an "AS
16*7c478bd9Sstevel@tonic-gate  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
17*7c478bd9Sstevel@tonic-gate  * implied. See the License for the specific language governing
18*7c478bd9Sstevel@tonic-gate  * rights and limitations under the License.
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * The Original Code is Mozilla Communicator client code, released
21*7c478bd9Sstevel@tonic-gate  * March 31, 1998.
22*7c478bd9Sstevel@tonic-gate  *
23*7c478bd9Sstevel@tonic-gate  * The Initial Developer of the Original Code is Netscape
24*7c478bd9Sstevel@tonic-gate  * Communications Corporation. Portions created by Netscape are
25*7c478bd9Sstevel@tonic-gate  * Copyright (C) 1998-1999 Netscape Communications Corporation. All
26*7c478bd9Sstevel@tonic-gate  * Rights Reserved.
27*7c478bd9Sstevel@tonic-gate  *
28*7c478bd9Sstevel@tonic-gate  * Contributor(s):
29*7c478bd9Sstevel@tonic-gate  */
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate /*
32*7c478bd9Sstevel@tonic-gate  * Thread callback functions for libldap that use the NSPR (Netscape
33*7c478bd9Sstevel@tonic-gate  * Portable Runtime) thread API.
34*7c478bd9Sstevel@tonic-gate  *
35*7c478bd9Sstevel@tonic-gate  */
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate #ifdef _SOLARIS_SDK
38*7c478bd9Sstevel@tonic-gate #include <thread.h>
39*7c478bd9Sstevel@tonic-gate #include <synch.h>
40*7c478bd9Sstevel@tonic-gate #include <prinit.h>
41*7c478bd9Sstevel@tonic-gate #include <prthread.h>
42*7c478bd9Sstevel@tonic-gate #include <syslog.h>
43*7c478bd9Sstevel@tonic-gate #include <string.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
45*7c478bd9Sstevel@tonic-gate #include <signal.h>
46*7c478bd9Sstevel@tonic-gate #include <errno.h>
47*7c478bd9Sstevel@tonic-gate extern int	errno;
48*7c478bd9Sstevel@tonic-gate #endif	/* _SOLARIS_SDK */
49*7c478bd9Sstevel@tonic-gate 
50*7c478bd9Sstevel@tonic-gate #include "ldappr-int.h"
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate #ifndef _SOLARIS_SDK
53*7c478bd9Sstevel@tonic-gate /*
54*7c478bd9Sstevel@tonic-gate  * Macros:
55*7c478bd9Sstevel@tonic-gate  */
56*7c478bd9Sstevel@tonic-gate /*
57*7c478bd9Sstevel@tonic-gate  * Grow thread private data arrays 10 elements at a time.
58*7c478bd9Sstevel@tonic-gate  */
59*7c478bd9Sstevel@tonic-gate #define PRLDAP_TPD_ARRAY_INCREMENT	10
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate /*
62*7c478bd9Sstevel@tonic-gate  * Structures and types:
63*7c478bd9Sstevel@tonic-gate  */
64*7c478bd9Sstevel@tonic-gate /*
65*7c478bd9Sstevel@tonic-gate  * Structure used by libldap thread callbacks to maintain error information.
66*7c478bd9Sstevel@tonic-gate  */
67*7c478bd9Sstevel@tonic-gate typedef struct prldap_errorinfo {
68*7c478bd9Sstevel@tonic-gate     int		plei_lderrno;
69*7c478bd9Sstevel@tonic-gate     char	*plei_matched;
70*7c478bd9Sstevel@tonic-gate     char	*plei_errmsg;
71*7c478bd9Sstevel@tonic-gate } PRLDAP_ErrorInfo;
72*7c478bd9Sstevel@tonic-gate 
73*7c478bd9Sstevel@tonic-gate /*
74*7c478bd9Sstevel@tonic-gate  * Structure used to maintain thread-private data. At the present time,
75*7c478bd9Sstevel@tonic-gate  * only error info. is thread-private.  One of these structures is allocated
76*7c478bd9Sstevel@tonic-gate  * for each thread.
77*7c478bd9Sstevel@tonic-gate  */
78*7c478bd9Sstevel@tonic-gate typedef struct prldap_tpd_header {
79*7c478bd9Sstevel@tonic-gate     int			ptpdh_tpd_count;	/* # of data items allocated */
80*7c478bd9Sstevel@tonic-gate     void		**ptpdh_dataitems;	/* array of data items */
81*7c478bd9Sstevel@tonic-gate } PRLDAP_TPDHeader;
82*7c478bd9Sstevel@tonic-gate 
83*7c478bd9Sstevel@tonic-gate /*
84*7c478bd9Sstevel@tonic-gate  * Structure used by associate a PRLDAP thread-private data index with an
85*7c478bd9Sstevel@tonic-gate  * LDAP session handle. One of these exists for each active LDAP session
86*7c478bd9Sstevel@tonic-gate  * handle.
87*7c478bd9Sstevel@tonic-gate  */
88*7c478bd9Sstevel@tonic-gate typedef struct prldap_tpd_map {
89*7c478bd9Sstevel@tonic-gate     LDAP			*prtm_ld;	/* non-NULL if in use */
90*7c478bd9Sstevel@tonic-gate     PRUintn			prtm_index;	/* index into TPD array */
91*7c478bd9Sstevel@tonic-gate     struct prldap_tpd_map	*prtm_next;
92*7c478bd9Sstevel@tonic-gate } PRLDAP_TPDMap;
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate #ifdef _SOLARIS_SDK
95*7c478bd9Sstevel@tonic-gate extern  mutex_t         inited_mutex;
96*7c478bd9Sstevel@tonic-gate #endif  /* _SOLARIS_SDK */
97*7c478bd9Sstevel@tonic-gate 
98*7c478bd9Sstevel@tonic-gate /*
99*7c478bd9Sstevel@tonic-gate  * Static Variables:
100*7c478bd9Sstevel@tonic-gate  */
101*7c478bd9Sstevel@tonic-gate /*
102*7c478bd9Sstevel@tonic-gate  * prldap_map_list points to all of the PRLDAP_TPDMap structures
103*7c478bd9Sstevel@tonic-gate  * we have ever allocated.  We recycle them as we open and close LDAP
104*7c478bd9Sstevel@tonic-gate  * sessions.
105*7c478bd9Sstevel@tonic-gate  */
106*7c478bd9Sstevel@tonic-gate static PRLDAP_TPDMap *prldap_map_list = NULL;
107*7c478bd9Sstevel@tonic-gate 
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate /*
110*7c478bd9Sstevel@tonic-gate  * The prldap_map_mutex is used to protect access to the prldap_map_list.
111*7c478bd9Sstevel@tonic-gate  */
112*7c478bd9Sstevel@tonic-gate static PRLock	*prldap_map_mutex = NULL;
113*7c478bd9Sstevel@tonic-gate 
114*7c478bd9Sstevel@tonic-gate /*
115*7c478bd9Sstevel@tonic-gate  * The prldap_tpd_maxindex value is used to track the largest TPD array
116*7c478bd9Sstevel@tonic-gate  * index we have used.
117*7c478bd9Sstevel@tonic-gate  */
118*7c478bd9Sstevel@tonic-gate static PRInt32	prldap_tpd_maxindex = -1;
119*7c478bd9Sstevel@tonic-gate 
120*7c478bd9Sstevel@tonic-gate /*
121*7c478bd9Sstevel@tonic-gate  * prldap_tpdindex is an NSPR thread private data index we use to
122*7c478bd9Sstevel@tonic-gate  * maintain our own thread-private data. It is initialized inside
123*7c478bd9Sstevel@tonic-gate  * prldap_init_tpd().
124*7c478bd9Sstevel@tonic-gate  */
125*7c478bd9Sstevel@tonic-gate static PRUintn	prldap_tpdindex = 0;
126*7c478bd9Sstevel@tonic-gate 
127*7c478bd9Sstevel@tonic-gate /*
128*7c478bd9Sstevel@tonic-gate  * The prldap_callonce_init_tpd structure is used by NSPR to ensure
129*7c478bd9Sstevel@tonic-gate  * that prldap_init_tpd() is called at most once.
130*7c478bd9Sstevel@tonic-gate  */
131*7c478bd9Sstevel@tonic-gate static PRCallOnceType prldap_callonce_init_tpd = { 0, 0, 0 };
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate 
134*7c478bd9Sstevel@tonic-gate /*
135*7c478bd9Sstevel@tonic-gate  * Private function prototypes:
136*7c478bd9Sstevel@tonic-gate  */
137*7c478bd9Sstevel@tonic-gate static void prldap_set_ld_error( int err, char *matched, char *errmsg,
138*7c478bd9Sstevel@tonic-gate 	void *errorarg );
139*7c478bd9Sstevel@tonic-gate static int prldap_get_ld_error( char **matchedp, char **errmsgp,
140*7c478bd9Sstevel@tonic-gate 	void *errorarg );
141*7c478bd9Sstevel@tonic-gate #endif
142*7c478bd9Sstevel@tonic-gate static void *prldap_mutex_alloc( void );
143*7c478bd9Sstevel@tonic-gate static void prldap_mutex_free( void *mutex );
144*7c478bd9Sstevel@tonic-gate static int prldap_mutex_lock( void *mutex );
145*7c478bd9Sstevel@tonic-gate static int prldap_mutex_unlock( void *mutex );
146*7c478bd9Sstevel@tonic-gate static void *prldap_get_thread_id( void );
147*7c478bd9Sstevel@tonic-gate #ifndef _SOLARIS_SDK
148*7c478bd9Sstevel@tonic-gate static PRStatus prldap_init_tpd( void );
149*7c478bd9Sstevel@tonic-gate static PRLDAP_TPDMap *prldap_allocate_map( LDAP *ld );
150*7c478bd9Sstevel@tonic-gate static void prldap_return_map( PRLDAP_TPDMap *map );
151*7c478bd9Sstevel@tonic-gate static PRUintn prldap_new_tpdindex( void );
152*7c478bd9Sstevel@tonic-gate static int prldap_set_thread_private( PRInt32 tpdindex, void *priv );
153*7c478bd9Sstevel@tonic-gate static void *prldap_get_thread_private( PRInt32 tpdindex );
154*7c478bd9Sstevel@tonic-gate static PRLDAP_TPDHeader *prldap_tsd_realloc( PRLDAP_TPDHeader *tsdhdr,
155*7c478bd9Sstevel@tonic-gate 	int maxindex );
156*7c478bd9Sstevel@tonic-gate static void prldap_tsd_destroy( void *priv );
157*7c478bd9Sstevel@tonic-gate #endif
158*7c478bd9Sstevel@tonic-gate 
159*7c478bd9Sstevel@tonic-gate 
160*7c478bd9Sstevel@tonic-gate /*
161*7c478bd9Sstevel@tonic-gate  * Install NSPR thread functions into ld (if ld is NULL, they are installed
162*7c478bd9Sstevel@tonic-gate  * as the default functions for new LDAP * handles).
163*7c478bd9Sstevel@tonic-gate  *
164*7c478bd9Sstevel@tonic-gate  * Returns 0 if all goes well and -1 if not.
165*7c478bd9Sstevel@tonic-gate  */
166*7c478bd9Sstevel@tonic-gate int
167*7c478bd9Sstevel@tonic-gate prldap_install_thread_functions( LDAP *ld, int shared )
168*7c478bd9Sstevel@tonic-gate {
169*7c478bd9Sstevel@tonic-gate     struct ldap_thread_fns		tfns;
170*7c478bd9Sstevel@tonic-gate     struct ldap_extra_thread_fns	xtfns;
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate #ifndef _SOLARIS_SDK
173*7c478bd9Sstevel@tonic-gate     if ( PR_CallOnce( &prldap_callonce_init_tpd, prldap_init_tpd )
174*7c478bd9Sstevel@tonic-gate 		!= PR_SUCCESS ) {
175*7c478bd9Sstevel@tonic-gate 	ldap_set_lderrno( ld, LDAP_LOCAL_ERROR, NULL, NULL );
176*7c478bd9Sstevel@tonic-gate 	return( -1 );
177*7c478bd9Sstevel@tonic-gate     }
178*7c478bd9Sstevel@tonic-gate #endif	/* _SOLARIS_SDK */
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate     /* set thread function pointers */
181*7c478bd9Sstevel@tonic-gate     memset( &tfns, '\0', sizeof(struct ldap_thread_fns) );
182*7c478bd9Sstevel@tonic-gate     tfns.ltf_get_errno = prldap_get_system_errno;
183*7c478bd9Sstevel@tonic-gate     tfns.ltf_set_errno = prldap_set_system_errno;
184*7c478bd9Sstevel@tonic-gate     if ( shared ) {
185*7c478bd9Sstevel@tonic-gate 	tfns.ltf_mutex_alloc = prldap_mutex_alloc;
186*7c478bd9Sstevel@tonic-gate 	tfns.ltf_mutex_free = prldap_mutex_free;
187*7c478bd9Sstevel@tonic-gate 	tfns.ltf_mutex_lock = prldap_mutex_lock;
188*7c478bd9Sstevel@tonic-gate 	tfns.ltf_mutex_unlock = prldap_mutex_unlock;
189*7c478bd9Sstevel@tonic-gate #ifdef _SOLARIS_SDK
190*7c478bd9Sstevel@tonic-gate 	tfns.ltf_get_lderrno = NULL;
191*7c478bd9Sstevel@tonic-gate 	tfns.ltf_set_lderrno = NULL;
192*7c478bd9Sstevel@tonic-gate #else
193*7c478bd9Sstevel@tonic-gate 	tfns.ltf_get_lderrno = prldap_get_ld_error;
194*7c478bd9Sstevel@tonic-gate 	tfns.ltf_set_lderrno = prldap_set_ld_error;
195*7c478bd9Sstevel@tonic-gate 	if ( ld != NULL ) {
196*7c478bd9Sstevel@tonic-gate 	    /*
197*7c478bd9Sstevel@tonic-gate 	     * If this is a real ld (i.e., we are not setting the global
198*7c478bd9Sstevel@tonic-gate 	     * defaults) allocate thread private data for error information.
199*7c478bd9Sstevel@tonic-gate 	     * If ld is NULL we do not do this here but it is done in
200*7c478bd9Sstevel@tonic-gate 	     * prldap_thread_new_handle().
201*7c478bd9Sstevel@tonic-gate 	     */
202*7c478bd9Sstevel@tonic-gate 	    if (( tfns.ltf_lderrno_arg = (void *)prldap_allocate_map( ld ))
203*7c478bd9Sstevel@tonic-gate 		    == NULL ) {
204*7c478bd9Sstevel@tonic-gate 		return( -1 );
205*7c478bd9Sstevel@tonic-gate 	    }
206*7c478bd9Sstevel@tonic-gate 	}
207*7c478bd9Sstevel@tonic-gate #endif
208*7c478bd9Sstevel@tonic-gate     }
209*7c478bd9Sstevel@tonic-gate 
210*7c478bd9Sstevel@tonic-gate     if ( ldap_set_option( ld, LDAP_OPT_THREAD_FN_PTRS,
211*7c478bd9Sstevel@tonic-gate 	    (void *)&tfns ) != 0 ) {
212*7c478bd9Sstevel@tonic-gate #ifndef _SOLARIS_SDK
213*7c478bd9Sstevel@tonic-gate 	prldap_return_map( (PRLDAP_TPDMap *)tfns.ltf_lderrno_arg );
214*7c478bd9Sstevel@tonic-gate #endif
215*7c478bd9Sstevel@tonic-gate 	return( -1 );
216*7c478bd9Sstevel@tonic-gate     }
217*7c478bd9Sstevel@tonic-gate 
218*7c478bd9Sstevel@tonic-gate     /* set extended thread function pointers */
219*7c478bd9Sstevel@tonic-gate     memset( &xtfns, '\0', sizeof(struct ldap_extra_thread_fns) );
220*7c478bd9Sstevel@tonic-gate     xtfns.ltf_threadid_fn = prldap_get_thread_id;
221*7c478bd9Sstevel@tonic-gate     if ( ldap_set_option( ld, LDAP_OPT_EXTRA_THREAD_FN_PTRS,
222*7c478bd9Sstevel@tonic-gate 	    (void *)&xtfns ) != 0 ) {
223*7c478bd9Sstevel@tonic-gate 	return( -1 );
224*7c478bd9Sstevel@tonic-gate     }
225*7c478bd9Sstevel@tonic-gate 
226*7c478bd9Sstevel@tonic-gate     return( 0 );
227*7c478bd9Sstevel@tonic-gate }
228*7c478bd9Sstevel@tonic-gate 
229*7c478bd9Sstevel@tonic-gate 
230*7c478bd9Sstevel@tonic-gate static void *
231*7c478bd9Sstevel@tonic-gate prldap_mutex_alloc( void )
232*7c478bd9Sstevel@tonic-gate {
233*7c478bd9Sstevel@tonic-gate     return( (void *)PR_NewLock());
234*7c478bd9Sstevel@tonic-gate }
235*7c478bd9Sstevel@tonic-gate 
236*7c478bd9Sstevel@tonic-gate 
237*7c478bd9Sstevel@tonic-gate static void
238*7c478bd9Sstevel@tonic-gate prldap_mutex_free( void *mutex )
239*7c478bd9Sstevel@tonic-gate {
240*7c478bd9Sstevel@tonic-gate     PR_DestroyLock( (PRLock *)mutex );
241*7c478bd9Sstevel@tonic-gate }
242*7c478bd9Sstevel@tonic-gate 
243*7c478bd9Sstevel@tonic-gate 
244*7c478bd9Sstevel@tonic-gate static int
245*7c478bd9Sstevel@tonic-gate prldap_mutex_lock( void *mutex )
246*7c478bd9Sstevel@tonic-gate {
247*7c478bd9Sstevel@tonic-gate     PR_Lock( (PRLock *)mutex );
248*7c478bd9Sstevel@tonic-gate     return( 0 );
249*7c478bd9Sstevel@tonic-gate }
250*7c478bd9Sstevel@tonic-gate 
251*7c478bd9Sstevel@tonic-gate 
252*7c478bd9Sstevel@tonic-gate static int
253*7c478bd9Sstevel@tonic-gate prldap_mutex_unlock( void *mutex )
254*7c478bd9Sstevel@tonic-gate {
255*7c478bd9Sstevel@tonic-gate     if ( PR_Unlock( (PRLock *)mutex ) == PR_FAILURE ) {
256*7c478bd9Sstevel@tonic-gate 	return( -1 );
257*7c478bd9Sstevel@tonic-gate     }
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate     return( 0 );
260*7c478bd9Sstevel@tonic-gate }
261*7c478bd9Sstevel@tonic-gate 
262*7c478bd9Sstevel@tonic-gate 
263*7c478bd9Sstevel@tonic-gate static void *
264*7c478bd9Sstevel@tonic-gate prldap_get_thread_id( void )
265*7c478bd9Sstevel@tonic-gate {
266*7c478bd9Sstevel@tonic-gate #ifdef	_SOLARIS_SDK
267*7c478bd9Sstevel@tonic-gate 	return ((void *)thr_self());
268*7c478bd9Sstevel@tonic-gate #else
269*7c478bd9Sstevel@tonic-gate     return( (void *)PR_GetCurrentThread());
270*7c478bd9Sstevel@tonic-gate #endif
271*7c478bd9Sstevel@tonic-gate }
272*7c478bd9Sstevel@tonic-gate 
273*7c478bd9Sstevel@tonic-gate #ifndef	_SOLARIS_SDK
274*7c478bd9Sstevel@tonic-gate static int
275*7c478bd9Sstevel@tonic-gate prldap_get_ld_error( char **matchedp, char **errmsgp, void *errorarg )
276*7c478bd9Sstevel@tonic-gate {
277*7c478bd9Sstevel@tonic-gate     PRLDAP_TPDMap	*map;
278*7c478bd9Sstevel@tonic-gate     PRLDAP_ErrorInfo	*eip;
279*7c478bd9Sstevel@tonic-gate 
280*7c478bd9Sstevel@tonic-gate     if (( map = (PRLDAP_TPDMap *)errorarg ) != NULL && ( eip =
281*7c478bd9Sstevel@tonic-gate 	    (PRLDAP_ErrorInfo *)prldap_get_thread_private(
282*7c478bd9Sstevel@tonic-gate 	    map->prtm_index )) != NULL ) {
283*7c478bd9Sstevel@tonic-gate 	if ( matchedp != NULL ) {
284*7c478bd9Sstevel@tonic-gate 	    *matchedp = eip->plei_matched;
285*7c478bd9Sstevel@tonic-gate 	}
286*7c478bd9Sstevel@tonic-gate 	if ( errmsgp != NULL ) {
287*7c478bd9Sstevel@tonic-gate 	    *errmsgp = eip->plei_errmsg;
288*7c478bd9Sstevel@tonic-gate 	}
289*7c478bd9Sstevel@tonic-gate 	return( eip->plei_lderrno );
290*7c478bd9Sstevel@tonic-gate     } else {
291*7c478bd9Sstevel@tonic-gate 	if ( matchedp != NULL ) {
292*7c478bd9Sstevel@tonic-gate 	    *matchedp = NULL;
293*7c478bd9Sstevel@tonic-gate 	}
294*7c478bd9Sstevel@tonic-gate 	if ( errmsgp != NULL ) {
295*7c478bd9Sstevel@tonic-gate 	    *errmsgp = NULL;
296*7c478bd9Sstevel@tonic-gate 	}
297*7c478bd9Sstevel@tonic-gate 	return( LDAP_LOCAL_ERROR );	/* punt */
298*7c478bd9Sstevel@tonic-gate     }
299*7c478bd9Sstevel@tonic-gate }
300*7c478bd9Sstevel@tonic-gate 
301*7c478bd9Sstevel@tonic-gate 
302*7c478bd9Sstevel@tonic-gate static void
303*7c478bd9Sstevel@tonic-gate prldap_set_ld_error( int err, char *matched, char *errmsg, void *errorarg )
304*7c478bd9Sstevel@tonic-gate {
305*7c478bd9Sstevel@tonic-gate     PRLDAP_TPDMap	*map;
306*7c478bd9Sstevel@tonic-gate     PRLDAP_ErrorInfo	*eip;
307*7c478bd9Sstevel@tonic-gate 
308*7c478bd9Sstevel@tonic-gate     if (( map = (PRLDAP_TPDMap *)errorarg ) != NULL ) {
309*7c478bd9Sstevel@tonic-gate 	if (( eip = (PRLDAP_ErrorInfo *)prldap_get_thread_private(
310*7c478bd9Sstevel@tonic-gate 		map->prtm_index )) == NULL ) {
311*7c478bd9Sstevel@tonic-gate 	    /*
312*7c478bd9Sstevel@tonic-gate 	     * Error info. has not yet been allocated for this thread.
313*7c478bd9Sstevel@tonic-gate 	     * Do so now.  Note that we free this memory only for the
314*7c478bd9Sstevel@tonic-gate 	     * thread that calls prldap_thread_dispose_handle(), which
315*7c478bd9Sstevel@tonic-gate 	     * should be the one that called ldap_unbind() -- see
316*7c478bd9Sstevel@tonic-gate 	     * prldap_return_map().  Not freeing the memory used by
317*7c478bd9Sstevel@tonic-gate 	     * other threads is deemed acceptable since it will be
318*7c478bd9Sstevel@tonic-gate 	     * recycled and used by other LDAP sessions.  All of the
319*7c478bd9Sstevel@tonic-gate 	     * thread-private memory is freed when a thread exits
320*7c478bd9Sstevel@tonic-gate 	     * (inside the prldap_tsd_destroy() function).
321*7c478bd9Sstevel@tonic-gate 	     */
322*7c478bd9Sstevel@tonic-gate 	    eip = (PRLDAP_ErrorInfo *)PR_Calloc( 1,
323*7c478bd9Sstevel@tonic-gate 		    sizeof( PRLDAP_ErrorInfo ));
324*7c478bd9Sstevel@tonic-gate 	    if ( eip == NULL ) {
325*7c478bd9Sstevel@tonic-gate 		return;	/* punt */
326*7c478bd9Sstevel@tonic-gate 	    }
327*7c478bd9Sstevel@tonic-gate 	    (void)prldap_set_thread_private( map->prtm_index, eip );
328*7c478bd9Sstevel@tonic-gate 	}
329*7c478bd9Sstevel@tonic-gate 
330*7c478bd9Sstevel@tonic-gate 	eip->plei_lderrno = err;
331*7c478bd9Sstevel@tonic-gate 	if ( eip->plei_matched != NULL ) {
332*7c478bd9Sstevel@tonic-gate 	    ldap_memfree( eip->plei_matched );
333*7c478bd9Sstevel@tonic-gate 	}
334*7c478bd9Sstevel@tonic-gate 	eip->plei_matched = matched;
335*7c478bd9Sstevel@tonic-gate 	if ( eip->plei_errmsg != NULL ) {
336*7c478bd9Sstevel@tonic-gate 	    ldap_memfree( eip->plei_errmsg );
337*7c478bd9Sstevel@tonic-gate 	}
338*7c478bd9Sstevel@tonic-gate 	eip->plei_errmsg = errmsg;
339*7c478bd9Sstevel@tonic-gate     }
340*7c478bd9Sstevel@tonic-gate }
341*7c478bd9Sstevel@tonic-gate #endif
342*7c478bd9Sstevel@tonic-gate 
343*7c478bd9Sstevel@tonic-gate 
344*7c478bd9Sstevel@tonic-gate /*
345*7c478bd9Sstevel@tonic-gate  * Called when a new LDAP * session handle is allocated.
346*7c478bd9Sstevel@tonic-gate  * Allocate thread-private data for error information, but only if
347*7c478bd9Sstevel@tonic-gate  * it has not already been allocated and the get_ld_error callback has
348*7c478bd9Sstevel@tonic-gate  * been installed.  If ld is not NULL when prldap_install_thread_functions()
349*7c478bd9Sstevel@tonic-gate  * is called, we will have already allocated the thread-private data there.
350*7c478bd9Sstevel@tonic-gate  */
351*7c478bd9Sstevel@tonic-gate int
352*7c478bd9Sstevel@tonic-gate prldap_thread_new_handle( LDAP *ld, void *sessionarg )
353*7c478bd9Sstevel@tonic-gate {
354*7c478bd9Sstevel@tonic-gate     struct ldap_thread_fns	tfns;
355*7c478bd9Sstevel@tonic-gate 
356*7c478bd9Sstevel@tonic-gate #ifndef _SOLARIS_SDK
357*7c478bd9Sstevel@tonic-gate     if ( ldap_get_option( ld, LDAP_OPT_THREAD_FN_PTRS, (void *)&tfns ) != 0 ) {
358*7c478bd9Sstevel@tonic-gate 	return( LDAP_LOCAL_ERROR );
359*7c478bd9Sstevel@tonic-gate     }
360*7c478bd9Sstevel@tonic-gate 
361*7c478bd9Sstevel@tonic-gate     if ( tfns.ltf_lderrno_arg == NULL && tfns.ltf_get_lderrno != NULL ) {
362*7c478bd9Sstevel@tonic-gate 	if (( tfns.ltf_lderrno_arg = (void *)prldap_allocate_map( ld )) == NULL
363*7c478bd9Sstevel@tonic-gate 		|| ldap_set_option( ld, LDAP_OPT_THREAD_FN_PTRS,
364*7c478bd9Sstevel@tonic-gate 		(void *)&tfns ) != 0 ) {
365*7c478bd9Sstevel@tonic-gate 	    return( LDAP_LOCAL_ERROR );
366*7c478bd9Sstevel@tonic-gate 	}
367*7c478bd9Sstevel@tonic-gate     }
368*7c478bd9Sstevel@tonic-gate #endif
369*7c478bd9Sstevel@tonic-gate 
370*7c478bd9Sstevel@tonic-gate     return( LDAP_SUCCESS );
371*7c478bd9Sstevel@tonic-gate }
372*7c478bd9Sstevel@tonic-gate 
373*7c478bd9Sstevel@tonic-gate 
374*7c478bd9Sstevel@tonic-gate /*
375*7c478bd9Sstevel@tonic-gate  * Called when an LDAP * session handle is being destroyed.
376*7c478bd9Sstevel@tonic-gate  * Clean up our thread private data map.
377*7c478bd9Sstevel@tonic-gate  */
378*7c478bd9Sstevel@tonic-gate void
379*7c478bd9Sstevel@tonic-gate prldap_thread_dispose_handle( LDAP *ld, void *sessionarg )
380*7c478bd9Sstevel@tonic-gate {
381*7c478bd9Sstevel@tonic-gate #ifndef _SOLARIS_SDK
382*7c478bd9Sstevel@tonic-gate     struct ldap_thread_fns	tfns;
383*7c478bd9Sstevel@tonic-gate 
384*7c478bd9Sstevel@tonic-gate     if ( ldap_get_option( ld, LDAP_OPT_THREAD_FN_PTRS,
385*7c478bd9Sstevel@tonic-gate 	    (void *)&tfns ) == 0 &&
386*7c478bd9Sstevel@tonic-gate 	    tfns.ltf_lderrno_arg != NULL ) {
387*7c478bd9Sstevel@tonic-gate 	prldap_return_map( (PRLDAP_TPDMap *)tfns.ltf_lderrno_arg );
388*7c478bd9Sstevel@tonic-gate     }
389*7c478bd9Sstevel@tonic-gate #endif
390*7c478bd9Sstevel@tonic-gate }
391*7c478bd9Sstevel@tonic-gate 
392*7c478bd9Sstevel@tonic-gate 
393*7c478bd9Sstevel@tonic-gate #ifndef _SOLARIS_SDK
394*7c478bd9Sstevel@tonic-gate static PRStatus
395*7c478bd9Sstevel@tonic-gate prldap_init_tpd( void )
396*7c478bd9Sstevel@tonic-gate {
397*7c478bd9Sstevel@tonic-gate     if (( prldap_map_mutex = PR_NewLock()) == NULL || PR_NewThreadPrivateIndex(
398*7c478bd9Sstevel@tonic-gate 		&prldap_tpdindex, prldap_tsd_destroy ) != PR_SUCCESS ) {
399*7c478bd9Sstevel@tonic-gate 	return( PR_FAILURE );
400*7c478bd9Sstevel@tonic-gate     }
401*7c478bd9Sstevel@tonic-gate 
402*7c478bd9Sstevel@tonic-gate     prldap_map_list = NULL;
403*7c478bd9Sstevel@tonic-gate 
404*7c478bd9Sstevel@tonic-gate     return( PR_SUCCESS );
405*7c478bd9Sstevel@tonic-gate }
406*7c478bd9Sstevel@tonic-gate 
407*7c478bd9Sstevel@tonic-gate 
408*7c478bd9Sstevel@tonic-gate /*
409*7c478bd9Sstevel@tonic-gate  * Function: prldap_allocate_map()
410*7c478bd9Sstevel@tonic-gate  * Description: allocate a thread-private data map to use for a new
411*7c478bd9Sstevel@tonic-gate  *	LDAP session handle.
412*7c478bd9Sstevel@tonic-gate  * Returns: a pointer to the TPD map or NULL if none available.
413*7c478bd9Sstevel@tonic-gate  */
414*7c478bd9Sstevel@tonic-gate static PRLDAP_TPDMap *
415*7c478bd9Sstevel@tonic-gate prldap_allocate_map( LDAP *ld )
416*7c478bd9Sstevel@tonic-gate {
417*7c478bd9Sstevel@tonic-gate     PRLDAP_TPDMap	*map, *prevmap;
418*7c478bd9Sstevel@tonic-gate 
419*7c478bd9Sstevel@tonic-gate     PR_Lock( prldap_map_mutex );
420*7c478bd9Sstevel@tonic-gate 
421*7c478bd9Sstevel@tonic-gate     /*
422*7c478bd9Sstevel@tonic-gate      * first look for a map that is already allocated but free to be re-used
423*7c478bd9Sstevel@tonic-gate      */
424*7c478bd9Sstevel@tonic-gate     prevmap = NULL;
425*7c478bd9Sstevel@tonic-gate     for ( map = prldap_map_list; map != NULL; map = map->prtm_next ) {
426*7c478bd9Sstevel@tonic-gate 	if ( map->prtm_ld == NULL ) {
427*7c478bd9Sstevel@tonic-gate 	    break;
428*7c478bd9Sstevel@tonic-gate 	}
429*7c478bd9Sstevel@tonic-gate 	prevmap = map;
430*7c478bd9Sstevel@tonic-gate     }
431*7c478bd9Sstevel@tonic-gate 
432*7c478bd9Sstevel@tonic-gate     /*
433*7c478bd9Sstevel@tonic-gate      * if none we found (map == NULL), try to allocate a new one and add it
434*7c478bd9Sstevel@tonic-gate      * to the end of our global list.
435*7c478bd9Sstevel@tonic-gate      */
436*7c478bd9Sstevel@tonic-gate     if ( map == NULL ) {
437*7c478bd9Sstevel@tonic-gate 	PRUintn	tpdindex;
438*7c478bd9Sstevel@tonic-gate 
439*7c478bd9Sstevel@tonic-gate 	tpdindex = prldap_new_tpdindex();
440*7c478bd9Sstevel@tonic-gate 	map = (PRLDAP_TPDMap *)PR_Malloc( sizeof( PRLDAP_TPDMap ));
441*7c478bd9Sstevel@tonic-gate 	if ( map != NULL ) {
442*7c478bd9Sstevel@tonic-gate 	    map->prtm_index = tpdindex;
443*7c478bd9Sstevel@tonic-gate 	    map->prtm_next = NULL;
444*7c478bd9Sstevel@tonic-gate 	    if ( prevmap == NULL ) {
445*7c478bd9Sstevel@tonic-gate 		prldap_map_list = map;
446*7c478bd9Sstevel@tonic-gate 	    } else {
447*7c478bd9Sstevel@tonic-gate 		prevmap->prtm_next = map;
448*7c478bd9Sstevel@tonic-gate 	    }
449*7c478bd9Sstevel@tonic-gate 	}
450*7c478bd9Sstevel@tonic-gate     }
451*7c478bd9Sstevel@tonic-gate 
452*7c478bd9Sstevel@tonic-gate     if ( map != NULL ) {
453*7c478bd9Sstevel@tonic-gate 	map->prtm_ld = ld;	/* now marked as "in use" */
454*7c478bd9Sstevel@tonic-gate 				/* since we are reusing...reset */
455*7c478bd9Sstevel@tonic-gate 				/* to initial state */
456*7c478bd9Sstevel@tonic-gate 	(void)prldap_set_thread_private( map->prtm_index, NULL );
457*7c478bd9Sstevel@tonic-gate     }
458*7c478bd9Sstevel@tonic-gate 
459*7c478bd9Sstevel@tonic-gate     PR_Unlock( prldap_map_mutex );
460*7c478bd9Sstevel@tonic-gate 
461*7c478bd9Sstevel@tonic-gate     return( map );
462*7c478bd9Sstevel@tonic-gate }
463*7c478bd9Sstevel@tonic-gate 
464*7c478bd9Sstevel@tonic-gate 
465*7c478bd9Sstevel@tonic-gate /*
466*7c478bd9Sstevel@tonic-gate  * Function: prldap_return_map()
467*7c478bd9Sstevel@tonic-gate  * Description: return a thread-private data map to the pool of ones
468*7c478bd9Sstevel@tonic-gate  *	available for re-use.
469*7c478bd9Sstevel@tonic-gate  */
470*7c478bd9Sstevel@tonic-gate static void
471*7c478bd9Sstevel@tonic-gate prldap_return_map( PRLDAP_TPDMap *map )
472*7c478bd9Sstevel@tonic-gate {
473*7c478bd9Sstevel@tonic-gate     PRLDAP_ErrorInfo	*eip;
474*7c478bd9Sstevel@tonic-gate 
475*7c478bd9Sstevel@tonic-gate     PR_Lock( prldap_map_mutex );
476*7c478bd9Sstevel@tonic-gate 
477*7c478bd9Sstevel@tonic-gate     /*
478*7c478bd9Sstevel@tonic-gate      * Dispose of thread-private LDAP error information.  Note that this
479*7c478bd9Sstevel@tonic-gate      * only disposes of the memory consumed on THIS thread, but that is
480*7c478bd9Sstevel@tonic-gate      * okay.  See the comment in prldap_set_ld_error() for the reason why.
481*7c478bd9Sstevel@tonic-gate      */
482*7c478bd9Sstevel@tonic-gate     if (( eip = (PRLDAP_ErrorInfo *)prldap_get_thread_private(
483*7c478bd9Sstevel@tonic-gate 		map->prtm_index )) != NULL &&
484*7c478bd9Sstevel@tonic-gate 		prldap_set_thread_private( map->prtm_index, NULL ) == 0 ) {
485*7c478bd9Sstevel@tonic-gate 	if ( eip->plei_matched != NULL ) {
486*7c478bd9Sstevel@tonic-gate 	    ldap_memfree( eip->plei_matched );
487*7c478bd9Sstevel@tonic-gate 	}
488*7c478bd9Sstevel@tonic-gate 	if ( eip->plei_errmsg != NULL ) {
489*7c478bd9Sstevel@tonic-gate 	    ldap_memfree( eip->plei_errmsg );
490*7c478bd9Sstevel@tonic-gate 	}
491*7c478bd9Sstevel@tonic-gate 
492*7c478bd9Sstevel@tonic-gate 	PR_Free( eip );
493*7c478bd9Sstevel@tonic-gate     }
494*7c478bd9Sstevel@tonic-gate 
495*7c478bd9Sstevel@tonic-gate     /* mark map as available for re-use */
496*7c478bd9Sstevel@tonic-gate     map->prtm_ld = NULL;
497*7c478bd9Sstevel@tonic-gate 
498*7c478bd9Sstevel@tonic-gate     PR_Unlock( prldap_map_mutex );
499*7c478bd9Sstevel@tonic-gate }
500*7c478bd9Sstevel@tonic-gate 
501*7c478bd9Sstevel@tonic-gate 
502*7c478bd9Sstevel@tonic-gate /*
503*7c478bd9Sstevel@tonic-gate  * Function: prldap_new_tpdindex()
504*7c478bd9Sstevel@tonic-gate  * Description: allocate a thread-private data index.
505*7c478bd9Sstevel@tonic-gate  * Returns: the new index.
506*7c478bd9Sstevel@tonic-gate  */
507*7c478bd9Sstevel@tonic-gate static PRUintn
508*7c478bd9Sstevel@tonic-gate prldap_new_tpdindex( void )
509*7c478bd9Sstevel@tonic-gate {
510*7c478bd9Sstevel@tonic-gate     PRUintn	tpdindex;
511*7c478bd9Sstevel@tonic-gate 
512*7c478bd9Sstevel@tonic-gate     tpdindex = (PRUintn)PR_AtomicIncrement( &prldap_tpd_maxindex );
513*7c478bd9Sstevel@tonic-gate     return( tpdindex );
514*7c478bd9Sstevel@tonic-gate }
515*7c478bd9Sstevel@tonic-gate 
516*7c478bd9Sstevel@tonic-gate 
517*7c478bd9Sstevel@tonic-gate /*
518*7c478bd9Sstevel@tonic-gate  * Function: prldap_set_thread_private()
519*7c478bd9Sstevel@tonic-gate  * Description: store a piece of thread-private data.
520*7c478bd9Sstevel@tonic-gate  * Returns: 0 if successful and -1 if not.
521*7c478bd9Sstevel@tonic-gate  */
522*7c478bd9Sstevel@tonic-gate static int
523*7c478bd9Sstevel@tonic-gate prldap_set_thread_private( PRInt32 tpdindex, void *priv )
524*7c478bd9Sstevel@tonic-gate {
525*7c478bd9Sstevel@tonic-gate     PRLDAP_TPDHeader	*tsdhdr;
526*7c478bd9Sstevel@tonic-gate 
527*7c478bd9Sstevel@tonic-gate     if ( tpdindex > prldap_tpd_maxindex ) {
528*7c478bd9Sstevel@tonic-gate 	return( -1 );	/* bad index */
529*7c478bd9Sstevel@tonic-gate     }
530*7c478bd9Sstevel@tonic-gate 
531*7c478bd9Sstevel@tonic-gate     tsdhdr = (PRLDAP_TPDHeader *)PR_GetThreadPrivate( prldap_tpdindex );
532*7c478bd9Sstevel@tonic-gate     if ( tsdhdr == NULL || tpdindex >= tsdhdr->ptpdh_tpd_count ) {
533*7c478bd9Sstevel@tonic-gate 	tsdhdr = prldap_tsd_realloc( tsdhdr, tpdindex );
534*7c478bd9Sstevel@tonic-gate 	if ( tsdhdr == NULL ) {
535*7c478bd9Sstevel@tonic-gate 	    return( -1 );	/* realloc failed */
536*7c478bd9Sstevel@tonic-gate 	}
537*7c478bd9Sstevel@tonic-gate     }
538*7c478bd9Sstevel@tonic-gate 
539*7c478bd9Sstevel@tonic-gate     tsdhdr->ptpdh_dataitems[ tpdindex ] = priv;
540*7c478bd9Sstevel@tonic-gate     return( 0 );
541*7c478bd9Sstevel@tonic-gate }
542*7c478bd9Sstevel@tonic-gate 
543*7c478bd9Sstevel@tonic-gate 
544*7c478bd9Sstevel@tonic-gate /*
545*7c478bd9Sstevel@tonic-gate  * Function: prldap_get_thread_private()
546*7c478bd9Sstevel@tonic-gate  * Description: retrieve a piece of thread-private data.  If not set,
547*7c478bd9Sstevel@tonic-gate  *	NULL is returned.
548*7c478bd9Sstevel@tonic-gate  * Returns: 0 if successful and -1 if not.
549*7c478bd9Sstevel@tonic-gate  */
550*7c478bd9Sstevel@tonic-gate static void *
551*7c478bd9Sstevel@tonic-gate prldap_get_thread_private( PRInt32 tpdindex )
552*7c478bd9Sstevel@tonic-gate {
553*7c478bd9Sstevel@tonic-gate     PRLDAP_TPDHeader	*tsdhdr;
554*7c478bd9Sstevel@tonic-gate 
555*7c478bd9Sstevel@tonic-gate     tsdhdr = (PRLDAP_TPDHeader *)PR_GetThreadPrivate( prldap_tpdindex );
556*7c478bd9Sstevel@tonic-gate     if ( tsdhdr == NULL ) {
557*7c478bd9Sstevel@tonic-gate 	return( NULL );	/* no thread private data */
558*7c478bd9Sstevel@tonic-gate     }
559*7c478bd9Sstevel@tonic-gate 
560*7c478bd9Sstevel@tonic-gate     if ( tpdindex >= tsdhdr->ptpdh_tpd_count
561*7c478bd9Sstevel@tonic-gate 		|| tsdhdr->ptpdh_dataitems == NULL ) {
562*7c478bd9Sstevel@tonic-gate 	return( NULL );	/* fewer data items than requested index */
563*7c478bd9Sstevel@tonic-gate     }
564*7c478bd9Sstevel@tonic-gate 
565*7c478bd9Sstevel@tonic-gate     return( tsdhdr->ptpdh_dataitems[ tpdindex ] );
566*7c478bd9Sstevel@tonic-gate }
567*7c478bd9Sstevel@tonic-gate 
568*7c478bd9Sstevel@tonic-gate 
569*7c478bd9Sstevel@tonic-gate /*
570*7c478bd9Sstevel@tonic-gate  * Function: prldap_tsd_realloc()
571*7c478bd9Sstevel@tonic-gate  * Description: enlarge the thread-private data array.
572*7c478bd9Sstevel@tonic-gate  * Returns: the new PRLDAP_TPDHeader value (non-NULL if successful).
573*7c478bd9Sstevel@tonic-gate  * Note: tsdhdr can be NULL (allocates a new PRLDAP_TPDHeader).
574*7c478bd9Sstevel@tonic-gate  */
575*7c478bd9Sstevel@tonic-gate static PRLDAP_TPDHeader *
576*7c478bd9Sstevel@tonic-gate prldap_tsd_realloc( PRLDAP_TPDHeader *tsdhdr, int maxindex )
577*7c478bd9Sstevel@tonic-gate {
578*7c478bd9Sstevel@tonic-gate     void	*newdataitems = NULL;
579*7c478bd9Sstevel@tonic-gate     int		count;
580*7c478bd9Sstevel@tonic-gate 
581*7c478bd9Sstevel@tonic-gate     if ( tsdhdr == NULL ) {
582*7c478bd9Sstevel@tonic-gate 	/* allocate a new thread private data header */
583*7c478bd9Sstevel@tonic-gate 	if (( tsdhdr = PR_Calloc( 1, sizeof( PRLDAP_TPDHeader ))) == NULL ) {
584*7c478bd9Sstevel@tonic-gate 	    return( NULL );
585*7c478bd9Sstevel@tonic-gate 	}
586*7c478bd9Sstevel@tonic-gate 	(void)PR_SetThreadPrivate( prldap_tpdindex, tsdhdr );
587*7c478bd9Sstevel@tonic-gate     }
588*7c478bd9Sstevel@tonic-gate 
589*7c478bd9Sstevel@tonic-gate     /*
590*7c478bd9Sstevel@tonic-gate      * Make the size of the new array the next highest multiple of
591*7c478bd9Sstevel@tonic-gate      * the array increment value that is greater than maxindex.
592*7c478bd9Sstevel@tonic-gate      */
593*7c478bd9Sstevel@tonic-gate     count = PRLDAP_TPD_ARRAY_INCREMENT *
594*7c478bd9Sstevel@tonic-gate 		( 1 + ( maxindex / PRLDAP_TPD_ARRAY_INCREMENT ));
595*7c478bd9Sstevel@tonic-gate 
596*7c478bd9Sstevel@tonic-gate     /* increase the size of the data item array if necessary */
597*7c478bd9Sstevel@tonic-gate     if ( count > tsdhdr->ptpdh_tpd_count  ) {
598*7c478bd9Sstevel@tonic-gate 	newdataitems = (PRLDAP_ErrorInfo *)PR_Calloc( count, sizeof( void * ));
599*7c478bd9Sstevel@tonic-gate 	if ( newdataitems == NULL ) {
600*7c478bd9Sstevel@tonic-gate 	    return( NULL );
601*7c478bd9Sstevel@tonic-gate 	}
602*7c478bd9Sstevel@tonic-gate 	if ( tsdhdr->ptpdh_dataitems != NULL ) {	/* preserve old data */
603*7c478bd9Sstevel@tonic-gate 	    memcpy( newdataitems, tsdhdr->ptpdh_dataitems,
604*7c478bd9Sstevel@tonic-gate 			tsdhdr->ptpdh_tpd_count * sizeof( void * ));
605*7c478bd9Sstevel@tonic-gate 	    PR_Free( tsdhdr->ptpdh_dataitems );
606*7c478bd9Sstevel@tonic-gate 	}
607*7c478bd9Sstevel@tonic-gate 
608*7c478bd9Sstevel@tonic-gate 	tsdhdr->ptpdh_tpd_count = count;
609*7c478bd9Sstevel@tonic-gate 	tsdhdr->ptpdh_dataitems = newdataitems;
610*7c478bd9Sstevel@tonic-gate     }
611*7c478bd9Sstevel@tonic-gate 
612*7c478bd9Sstevel@tonic-gate     return( tsdhdr );
613*7c478bd9Sstevel@tonic-gate }
614*7c478bd9Sstevel@tonic-gate 
615*7c478bd9Sstevel@tonic-gate 
616*7c478bd9Sstevel@tonic-gate /*
617*7c478bd9Sstevel@tonic-gate  * Function: prldap_tsd_destroy()
618*7c478bd9Sstevel@tonic-gate  * Description: Free a thread-private data array. Installed as an NSPR TPD
619*7c478bd9Sstevel@tonic-gate  *	destructor function
620*7c478bd9Sstevel@tonic-gate  * Returns: nothing.
621*7c478bd9Sstevel@tonic-gate  * Note: this function assumes that each TPD item installed at the PRLDAP
622*7c478bd9Sstevel@tonic-gate  *	level can be freed with a call to PR_Free().
623*7c478bd9Sstevel@tonic-gate  */
624*7c478bd9Sstevel@tonic-gate static void
625*7c478bd9Sstevel@tonic-gate prldap_tsd_destroy( void *priv )
626*7c478bd9Sstevel@tonic-gate {
627*7c478bd9Sstevel@tonic-gate     PRLDAP_TPDHeader	*tsdhdr;
628*7c478bd9Sstevel@tonic-gate     int			i;
629*7c478bd9Sstevel@tonic-gate 
630*7c478bd9Sstevel@tonic-gate     tsdhdr = (PRLDAP_TPDHeader *)priv;
631*7c478bd9Sstevel@tonic-gate     if ( tsdhdr != NULL ) {
632*7c478bd9Sstevel@tonic-gate 	if ( tsdhdr->ptpdh_dataitems != NULL ) {
633*7c478bd9Sstevel@tonic-gate 	    for ( i = 0; i < tsdhdr->ptpdh_tpd_count; ++i ) {
634*7c478bd9Sstevel@tonic-gate 		if ( tsdhdr->ptpdh_dataitems[ i ] != NULL ) {
635*7c478bd9Sstevel@tonic-gate 		    PR_Free( tsdhdr->ptpdh_dataitems[ i ] );
636*7c478bd9Sstevel@tonic-gate 		    tsdhdr->ptpdh_dataitems[ i ] = NULL;
637*7c478bd9Sstevel@tonic-gate 		}
638*7c478bd9Sstevel@tonic-gate 	    }
639*7c478bd9Sstevel@tonic-gate 	    PR_Free( tsdhdr->ptpdh_dataitems );
640*7c478bd9Sstevel@tonic-gate 	    tsdhdr->ptpdh_dataitems = NULL;
641*7c478bd9Sstevel@tonic-gate 	}
642*7c478bd9Sstevel@tonic-gate 	PR_Free( tsdhdr );
643*7c478bd9Sstevel@tonic-gate     }
644*7c478bd9Sstevel@tonic-gate }
645*7c478bd9Sstevel@tonic-gate #endif
646*7c478bd9Sstevel@tonic-gate 
647*7c478bd9Sstevel@tonic-gate #ifdef	_SOLARIS_SDK
648*7c478bd9Sstevel@tonic-gate #pragma	init(prldap_nspr_init)
649*7c478bd9Sstevel@tonic-gate static mutex_t	nspr_init_lock = DEFAULTMUTEX;
650*7c478bd9Sstevel@tonic-gate static mutex_t	nspr_idle_lock = DEFAULTMUTEX;
651*7c478bd9Sstevel@tonic-gate static cond_t	nspr_idle_cond = DEFAULTCV;
652*7c478bd9Sstevel@tonic-gate static int	nspr_pr_init_is_done = 0;
653*7c478bd9Sstevel@tonic-gate static int	nspr_initialized = 0;
654*7c478bd9Sstevel@tonic-gate 
655*7c478bd9Sstevel@tonic-gate void *
656*7c478bd9Sstevel@tonic-gate prldap_nspr_idle_primordial_thread(void *arg) {
657*7c478bd9Sstevel@tonic-gate 	/*
658*7c478bd9Sstevel@tonic-gate 	 * Make sure PR_Init finishes before any other thread can continue
659*7c478bd9Sstevel@tonic-gate 	 */
660*7c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&nspr_idle_lock);
661*7c478bd9Sstevel@tonic-gate 	if (PR_Initialized() == PR_FALSE)
662*7c478bd9Sstevel@tonic-gate 		PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
663*7c478bd9Sstevel@tonic-gate 	nspr_pr_init_is_done = 1;
664*7c478bd9Sstevel@tonic-gate 	(void) cond_signal(&nspr_idle_cond);
665*7c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&nspr_idle_lock);
666*7c478bd9Sstevel@tonic-gate 
667*7c478bd9Sstevel@tonic-gate 	/* Debug only */
668*7c478bd9Sstevel@tonic-gate 	syslog(LOG_DEBUG, "NSPR is initialized by the"
669*7c478bd9Sstevel@tonic-gate 		"idle primordial thread tid %ld created by thread "
670*7c478bd9Sstevel@tonic-gate 		"tid %ld", thr_self(), (long)arg);
671*7c478bd9Sstevel@tonic-gate 	pause();
672*7c478bd9Sstevel@tonic-gate 
673*7c478bd9Sstevel@tonic-gate }
674*7c478bd9Sstevel@tonic-gate 
675*7c478bd9Sstevel@tonic-gate /*
676*7c478bd9Sstevel@tonic-gate  * Initialize NSPR once
677*7c478bd9Sstevel@tonic-gate  *
678*7c478bd9Sstevel@tonic-gate  * Ideally this should be done in .init of NSPR.
679*7c478bd9Sstevel@tonic-gate  * This is a workaround so only main thread can initialize
680*7c478bd9Sstevel@tonic-gate  * NSPR but main() does not need to call PR_Init().
681*7c478bd9Sstevel@tonic-gate  * The future direction is NSPR free so we don't want programs
682*7c478bd9Sstevel@tonic-gate  * to call PR_Init().
683*7c478bd9Sstevel@tonic-gate  *
684*7c478bd9Sstevel@tonic-gate  * For most of cases, programs link libldap (-lldap)
685*7c478bd9Sstevel@tonic-gate  * and .init is executed before the control is transfered to
686*7c478bd9Sstevel@tonic-gate  * main().
687*7c478bd9Sstevel@tonic-gate  * But for programs linking libnsl (-lnsl), libldap is loaded
688*7c478bd9Sstevel@tonic-gate  * via dlopen("nss_ldap.so.1", RTLD_LAZY) so the thread loads
689*7c478bd9Sstevel@tonic-gate  * libldap is not necessary a main or a primordial
690*7c478bd9Sstevel@tonic-gate  * thread. In the latter case, an idle primordial thread is created
691*7c478bd9Sstevel@tonic-gate  * to initialize NSPR so NSPR won't be initialized by non-primordial
692*7c478bd9Sstevel@tonic-gate  * threads.
693*7c478bd9Sstevel@tonic-gate  * libldap is built with "-z nodelete" so libldap and libnspr4.so
694*7c478bd9Sstevel@tonic-gate  * are persistent in the address space.
695*7c478bd9Sstevel@tonic-gate  */
696*7c478bd9Sstevel@tonic-gate void
697*7c478bd9Sstevel@tonic-gate prldap_nspr_init(void) {
698*7c478bd9Sstevel@tonic-gate 	struct sigaction	action;
699*7c478bd9Sstevel@tonic-gate 
700*7c478bd9Sstevel@tonic-gate 	/*
701*7c478bd9Sstevel@tonic-gate 	 * For performance reason, test it here first
702*7c478bd9Sstevel@tonic-gate 	 */
703*7c478bd9Sstevel@tonic-gate 	if (nspr_initialized != 0)
704*7c478bd9Sstevel@tonic-gate 		return;
705*7c478bd9Sstevel@tonic-gate 
706*7c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&nspr_init_lock);
707*7c478bd9Sstevel@tonic-gate 	/* Make sure PR_Init() is executed only once */
708*7c478bd9Sstevel@tonic-gate 	if (nspr_initialized == 0) {
709*7c478bd9Sstevel@tonic-gate 		/*
710*7c478bd9Sstevel@tonic-gate 		 * PR_Init changes the signal handler of SIGPIPE to SIG_IGN.
711*7c478bd9Sstevel@tonic-gate 		 * Save the original and restore it after PR_Init.
712*7c478bd9Sstevel@tonic-gate 		 */
713*7c478bd9Sstevel@tonic-gate 		(void) sigaction(SIGPIPE, NULL, &action);
714*7c478bd9Sstevel@tonic-gate 
715*7c478bd9Sstevel@tonic-gate 		if (thr_self() == 1) {
716*7c478bd9Sstevel@tonic-gate 			/* main thread */
717*7c478bd9Sstevel@tonic-gate 			if (PR_Initialized() == PR_FALSE)
718*7c478bd9Sstevel@tonic-gate  				PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
719*7c478bd9Sstevel@tonic-gate 			nspr_initialized = 1;
720*7c478bd9Sstevel@tonic-gate 		} else {
721*7c478bd9Sstevel@tonic-gate 			if (thr_create(NULL, NULL,
722*7c478bd9Sstevel@tonic-gate 				prldap_nspr_idle_primordial_thread,
723*7c478bd9Sstevel@tonic-gate 				(void *)thr_self(), THR_DETACHED, NULL) != 0) {
724*7c478bd9Sstevel@tonic-gate 					syslog(LOG_ERR,
725*7c478bd9Sstevel@tonic-gate 					"libldap:.init: Can't create thread. "
726*7c478bd9Sstevel@tonic-gate 					"%s", strerror(errno));
727*7c478bd9Sstevel@tonic-gate 			} else {
728*7c478bd9Sstevel@tonic-gate 			/*
729*7c478bd9Sstevel@tonic-gate 			 * Make sure PR_Init finishes before any other thread
730*7c478bd9Sstevel@tonic-gate 			 * can continue.
731*7c478bd9Sstevel@tonic-gate 			 * It's unlikely, but not impossible that this thread
732*7c478bd9Sstevel@tonic-gate 			 * finishes dlopen and  starts to call
733*7c478bd9Sstevel@tonic-gate 			 * LDAP API when the idle thread still has not
734*7c478bd9Sstevel@tonic-gate 			 * finished PR_Init() yet.
735*7c478bd9Sstevel@tonic-gate 			 */
736*7c478bd9Sstevel@tonic-gate 				(void) mutex_lock(&nspr_idle_lock);
737*7c478bd9Sstevel@tonic-gate 				while (nspr_pr_init_is_done == 0) {
738*7c478bd9Sstevel@tonic-gate 					(void) cond_wait(&nspr_idle_cond,
739*7c478bd9Sstevel@tonic-gate 							&nspr_idle_lock);
740*7c478bd9Sstevel@tonic-gate 
741*7c478bd9Sstevel@tonic-gate 				}
742*7c478bd9Sstevel@tonic-gate 				(void) mutex_unlock(&nspr_idle_lock);
743*7c478bd9Sstevel@tonic-gate 				nspr_initialized = 1;
744*7c478bd9Sstevel@tonic-gate 			}
745*7c478bd9Sstevel@tonic-gate 		}
746*7c478bd9Sstevel@tonic-gate 		/*
747*7c478bd9Sstevel@tonic-gate 		 * Restore signal handling attributes of SIGPIPE
748*7c478bd9Sstevel@tonic-gate 		 */
749*7c478bd9Sstevel@tonic-gate 		(void) sigaction(SIGPIPE, &action, NULL);
750*7c478bd9Sstevel@tonic-gate 
751*7c478bd9Sstevel@tonic-gate 	}
752*7c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&nspr_init_lock);
753*7c478bd9Sstevel@tonic-gate }
754*7c478bd9Sstevel@tonic-gate #endif
755