1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate * Copyright 2001-2003 Sun Microsystems, Inc. All rights reserved.
3*0Sstevel@tonic-gate * Use is subject to license terms.
4*0Sstevel@tonic-gate */
5*0Sstevel@tonic-gate
6*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
7*0Sstevel@tonic-gate
8*0Sstevel@tonic-gate /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
9*0Sstevel@tonic-gate *
10*0Sstevel@tonic-gate * The contents of this file are subject to the Netscape Public License
11*0Sstevel@tonic-gate * Version 1.0 (the "NPL"); you may not use this file except in
12*0Sstevel@tonic-gate * compliance with the NPL. You may obtain a copy of the NPL at
13*0Sstevel@tonic-gate * http://www.mozilla.org/NPL/
14*0Sstevel@tonic-gate *
15*0Sstevel@tonic-gate * Software distributed under the NPL is distributed on an "AS IS" basis,
16*0Sstevel@tonic-gate * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
17*0Sstevel@tonic-gate * for the specific language governing rights and limitations under the
18*0Sstevel@tonic-gate * NPL.
19*0Sstevel@tonic-gate *
20*0Sstevel@tonic-gate * The Initial Developer of this code under the NPL is Netscape
21*0Sstevel@tonic-gate * Communications Corporation. Portions created by Netscape are
22*0Sstevel@tonic-gate * Copyright (C) 1998 Netscape Communications Corporation. All Rights
23*0Sstevel@tonic-gate * Reserved.
24*0Sstevel@tonic-gate */
25*0Sstevel@tonic-gate /*
26*0Sstevel@tonic-gate * Copyright (c) 1990 Regents of the University of Michigan.
27*0Sstevel@tonic-gate * All rights reserved.
28*0Sstevel@tonic-gate */
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate * result.c - wait for an ldap result
31*0Sstevel@tonic-gate */
32*0Sstevel@tonic-gate
33*0Sstevel@tonic-gate #if 0
34*0Sstevel@tonic-gate #ifndef lint
35*0Sstevel@tonic-gate static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
36*0Sstevel@tonic-gate #endif
37*0Sstevel@tonic-gate #endif
38*0Sstevel@tonic-gate
39*0Sstevel@tonic-gate #include "ldap-int.h"
40*0Sstevel@tonic-gate
41*0Sstevel@tonic-gate #ifdef _SOLARIS_SDK
42*0Sstevel@tonic-gate /* high resolution timer usage */
43*0Sstevel@tonic-gate #include <sys/time.h>
44*0Sstevel@tonic-gate #endif
45*0Sstevel@tonic-gate
46*0Sstevel@tonic-gate static int check_response_queue( LDAP *ld, int msgid, int all,
47*0Sstevel@tonic-gate int do_abandon_check, LDAPMessage **result );
48*0Sstevel@tonic-gate static int ldap_abandoned( LDAP *ld, int msgid );
49*0Sstevel@tonic-gate static int ldap_mark_abandoned( LDAP *ld, int msgid );
50*0Sstevel@tonic-gate static int wait4msg( LDAP *ld, int msgid, int all, int unlock_permitted,
51*0Sstevel@tonic-gate struct timeval *timeout, LDAPMessage **result );
52*0Sstevel@tonic-gate static int read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb, LDAPConn *lc,
53*0Sstevel@tonic-gate LDAPMessage **result );
54*0Sstevel@tonic-gate static void check_for_refs( LDAP *ld, LDAPRequest *lr, BerElement *ber,
55*0Sstevel@tonic-gate int ldapversion, int *totalcountp, int *chasingcountp );
56*0Sstevel@tonic-gate static int build_result_ber( LDAP *ld, BerElement **berp, LDAPRequest *lr );
57*0Sstevel@tonic-gate static void merge_error_info( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr );
58*0Sstevel@tonic-gate #if defined( CLDAP )
59*0Sstevel@tonic-gate static int cldap_select1( LDAP *ld, struct timeval *timeout );
60*0Sstevel@tonic-gate #endif
61*0Sstevel@tonic-gate static void link_pend( LDAP *ld, LDAPPend *lp );
62*0Sstevel@tonic-gate #if 0 /* these functions are no longer used */
63*0Sstevel@tonic-gate static void unlink_pend( LDAP *ld, LDAPPend *lp );
64*0Sstevel@tonic-gate static int unlink_msg( LDAP *ld, int msgid, int all );
65*0Sstevel@tonic-gate #endif /* 0 */
66*0Sstevel@tonic-gate
67*0Sstevel@tonic-gate /*
68*0Sstevel@tonic-gate * ldap_result - wait for an ldap result response to a message from the
69*0Sstevel@tonic-gate * ldap server. If msgid is -1, any message will be accepted, otherwise
70*0Sstevel@tonic-gate * ldap_result will wait for a response with msgid. If all is 0 the
71*0Sstevel@tonic-gate * first message with id msgid will be accepted, otherwise, ldap_result
72*0Sstevel@tonic-gate * will wait for all responses with id msgid and then return a pointer to
73*0Sstevel@tonic-gate * the entire list of messages. This is only useful for search responses,
74*0Sstevel@tonic-gate * which can be of two message types (zero or more entries, followed by an
75*0Sstevel@tonic-gate * ldap result). The type of the first message received is returned.
76*0Sstevel@tonic-gate * When waiting, any messages that have been abandoned are discarded.
77*0Sstevel@tonic-gate *
78*0Sstevel@tonic-gate * Example:
79*0Sstevel@tonic-gate * ldap_result( s, msgid, all, timeout, result )
80*0Sstevel@tonic-gate */
81*0Sstevel@tonic-gate int
82*0Sstevel@tonic-gate LDAP_CALL
ldap_result(LDAP * ld,int msgid,int all,struct timeval * timeout,LDAPMessage ** result)83*0Sstevel@tonic-gate ldap_result(
84*0Sstevel@tonic-gate LDAP *ld,
85*0Sstevel@tonic-gate int msgid,
86*0Sstevel@tonic-gate int all,
87*0Sstevel@tonic-gate struct timeval *timeout,
88*0Sstevel@tonic-gate LDAPMessage **result
89*0Sstevel@tonic-gate )
90*0Sstevel@tonic-gate {
91*0Sstevel@tonic-gate int rc;
92*0Sstevel@tonic-gate
93*0Sstevel@tonic-gate LDAPDebug( LDAP_DEBUG_TRACE, "ldap_result\n", 0, 0, 0 );
94*0Sstevel@tonic-gate
95*0Sstevel@tonic-gate if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
96*0Sstevel@tonic-gate return( -1 ); /* punt */
97*0Sstevel@tonic-gate }
98*0Sstevel@tonic-gate
99*0Sstevel@tonic-gate LDAP_MUTEX_LOCK( ld, LDAP_RESULT_LOCK );
100*0Sstevel@tonic-gate
101*0Sstevel@tonic-gate rc = nsldapi_result_nolock(ld, msgid, all, 1, timeout, result);
102*0Sstevel@tonic-gate
103*0Sstevel@tonic-gate LDAP_MUTEX_UNLOCK( ld, LDAP_RESULT_LOCK );
104*0Sstevel@tonic-gate
105*0Sstevel@tonic-gate return( rc );
106*0Sstevel@tonic-gate }
107*0Sstevel@tonic-gate
108*0Sstevel@tonic-gate
109*0Sstevel@tonic-gate int
nsldapi_result_nolock(LDAP * ld,int msgid,int all,int unlock_permitted,struct timeval * timeout,LDAPMessage ** result)110*0Sstevel@tonic-gate nsldapi_result_nolock( LDAP *ld, int msgid, int all, int unlock_permitted,
111*0Sstevel@tonic-gate struct timeval *timeout, LDAPMessage **result )
112*0Sstevel@tonic-gate {
113*0Sstevel@tonic-gate int rc;
114*0Sstevel@tonic-gate
115*0Sstevel@tonic-gate LDAPDebug( LDAP_DEBUG_TRACE,
116*0Sstevel@tonic-gate "nsldapi_result_nolock (msgid=%d, all=%d)\n", msgid, all, 0 );
117*0Sstevel@tonic-gate
118*0Sstevel@tonic-gate /*
119*0Sstevel@tonic-gate * First, look through the list of responses we have received on
120*0Sstevel@tonic-gate * this association and see if the response we're interested in
121*0Sstevel@tonic-gate * is there. If it is, return it. If not, call wait4msg() to
122*0Sstevel@tonic-gate * wait until it arrives or timeout occurs.
123*0Sstevel@tonic-gate */
124*0Sstevel@tonic-gate
125*0Sstevel@tonic-gate if ( result == NULL ) {
126*0Sstevel@tonic-gate LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
127*0Sstevel@tonic-gate return( -1 );
128*0Sstevel@tonic-gate }
129*0Sstevel@tonic-gate
130*0Sstevel@tonic-gate if ( check_response_queue( ld, msgid, all, 1, result ) != 0 ) {
131*0Sstevel@tonic-gate LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, NULL );
132*0Sstevel@tonic-gate rc = (*result)->lm_msgtype;
133*0Sstevel@tonic-gate } else {
134*0Sstevel@tonic-gate rc = wait4msg( ld, msgid, all, unlock_permitted, timeout,
135*0Sstevel@tonic-gate result );
136*0Sstevel@tonic-gate }
137*0Sstevel@tonic-gate
138*0Sstevel@tonic-gate /*
139*0Sstevel@tonic-gate * XXXmcs should use cache function pointers to hook in memcache
140*0Sstevel@tonic-gate */
141*0Sstevel@tonic-gate if ( ld->ld_memcache != NULL && NSLDAPI_SEARCH_RELATED_RESULT( rc ) &&
142*0Sstevel@tonic-gate !((*result)->lm_fromcache )) {
143*0Sstevel@tonic-gate ldap_memcache_append( ld, (*result)->lm_msgid,
144*0Sstevel@tonic-gate (all || NSLDAPI_IS_SEARCH_RESULT( rc )), *result );
145*0Sstevel@tonic-gate }
146*0Sstevel@tonic-gate
147*0Sstevel@tonic-gate return( rc );
148*0Sstevel@tonic-gate }
149*0Sstevel@tonic-gate
150*0Sstevel@tonic-gate
151*0Sstevel@tonic-gate /*
152*0Sstevel@tonic-gate * Look through the list of queued responses for a message that matches the
153*0Sstevel@tonic-gate * criteria in the msgid and all parameters. msgid == LDAP_RES_ANY matches
154*0Sstevel@tonic-gate * all ids.
155*0Sstevel@tonic-gate *
156*0Sstevel@tonic-gate * If an appropriate message is found, a non-zero value is returned and the
157*0Sstevel@tonic-gate * message is dequeued and assigned to *result.
158*0Sstevel@tonic-gate *
159*0Sstevel@tonic-gate * If not, *result is set to NULL and this function returns 0.
160*0Sstevel@tonic-gate */
161*0Sstevel@tonic-gate static int
check_response_queue(LDAP * ld,int msgid,int all,int do_abandon_check,LDAPMessage ** result)162*0Sstevel@tonic-gate check_response_queue( LDAP *ld, int msgid, int all, int do_abandon_check,
163*0Sstevel@tonic-gate LDAPMessage **result )
164*0Sstevel@tonic-gate {
165*0Sstevel@tonic-gate LDAPMessage *lm, *lastlm, *nextlm;
166*0Sstevel@tonic-gate LDAPRequest *lr;
167*0Sstevel@tonic-gate
168*0Sstevel@tonic-gate LDAPDebug( LDAP_DEBUG_TRACE,
169*0Sstevel@tonic-gate "=> check_response_queue (msgid=%d, all=%d)\n", msgid, all, 0 );
170*0Sstevel@tonic-gate
171*0Sstevel@tonic-gate *result = NULL;
172*0Sstevel@tonic-gate lastlm = NULL;
173*0Sstevel@tonic-gate LDAP_MUTEX_LOCK( ld, LDAP_RESP_LOCK );
174*0Sstevel@tonic-gate for ( lm = ld->ld_responses; lm != NULL; lm = nextlm ) {
175*0Sstevel@tonic-gate nextlm = lm->lm_next;
176*0Sstevel@tonic-gate
177*0Sstevel@tonic-gate if ( do_abandon_check && ldap_abandoned( ld, lm->lm_msgid ) ) {
178*0Sstevel@tonic-gate ldap_mark_abandoned( ld, lm->lm_msgid );
179*0Sstevel@tonic-gate
180*0Sstevel@tonic-gate if ( lastlm == NULL ) {
181*0Sstevel@tonic-gate ld->ld_responses = lm->lm_next;
182*0Sstevel@tonic-gate } else {
183*0Sstevel@tonic-gate lastlm->lm_next = nextlm;
184*0Sstevel@tonic-gate }
185*0Sstevel@tonic-gate
186*0Sstevel@tonic-gate ldap_msgfree( lm );
187*0Sstevel@tonic-gate
188*0Sstevel@tonic-gate continue;
189*0Sstevel@tonic-gate }
190*0Sstevel@tonic-gate
191*0Sstevel@tonic-gate if ( msgid == LDAP_RES_ANY || lm->lm_msgid == msgid ) {
192*0Sstevel@tonic-gate LDAPMessage *tmp;
193*0Sstevel@tonic-gate
194*0Sstevel@tonic-gate if ( all == 0
195*0Sstevel@tonic-gate || (lm->lm_msgtype != LDAP_RES_SEARCH_RESULT
196*0Sstevel@tonic-gate && lm->lm_msgtype != LDAP_RES_SEARCH_REFERENCE
197*0Sstevel@tonic-gate && lm->lm_msgtype != LDAP_RES_SEARCH_ENTRY) )
198*0Sstevel@tonic-gate break;
199*0Sstevel@tonic-gate
200*0Sstevel@tonic-gate for ( tmp = lm; tmp != NULL; tmp = tmp->lm_chain ) {
201*0Sstevel@tonic-gate if ( tmp->lm_msgtype == LDAP_RES_SEARCH_RESULT )
202*0Sstevel@tonic-gate break;
203*0Sstevel@tonic-gate }
204*0Sstevel@tonic-gate
205*0Sstevel@tonic-gate if ( tmp == NULL ) {
206*0Sstevel@tonic-gate LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
207*0Sstevel@tonic-gate LDAPDebug( LDAP_DEBUG_TRACE,
208*0Sstevel@tonic-gate "<= check_response_queue NOT FOUND\n",
209*0Sstevel@tonic-gate 0, 0, 0 );
210*0Sstevel@tonic-gate return( 0 ); /* no message to return */
211*0Sstevel@tonic-gate }
212*0Sstevel@tonic-gate
213*0Sstevel@tonic-gate break;
214*0Sstevel@tonic-gate }
215*0Sstevel@tonic-gate lastlm = lm;
216*0Sstevel@tonic-gate }
217*0Sstevel@tonic-gate
218*0Sstevel@tonic-gate /*
219*0Sstevel@tonic-gate * if we did not find a message OR if the one we found is a result for
220*0Sstevel@tonic-gate * a request that is still pending, return failure.
221*0Sstevel@tonic-gate */
222*0Sstevel@tonic-gate if ( lm == NULL
223*0Sstevel@tonic-gate || (( lr = nsldapi_find_request_by_msgid( ld, lm->lm_msgid ))
224*0Sstevel@tonic-gate != NULL && lr->lr_outrefcnt > 0 )) {
225*0Sstevel@tonic-gate LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
226*0Sstevel@tonic-gate LDAPDebug( LDAP_DEBUG_TRACE,
227*0Sstevel@tonic-gate "<= check_response_queue NOT FOUND\n",
228*0Sstevel@tonic-gate 0, 0, 0 );
229*0Sstevel@tonic-gate return( 0 ); /* no message to return */
230*0Sstevel@tonic-gate }
231*0Sstevel@tonic-gate
232*0Sstevel@tonic-gate if ( all == 0 ) {
233*0Sstevel@tonic-gate if ( lm->lm_chain == NULL ) {
234*0Sstevel@tonic-gate if ( lastlm == NULL ) {
235*0Sstevel@tonic-gate ld->ld_responses = lm->lm_next;
236*0Sstevel@tonic-gate } else {
237*0Sstevel@tonic-gate lastlm->lm_next = lm->lm_next;
238*0Sstevel@tonic-gate }
239*0Sstevel@tonic-gate } else {
240*0Sstevel@tonic-gate if ( lastlm == NULL ) {
241*0Sstevel@tonic-gate ld->ld_responses = lm->lm_chain;
242*0Sstevel@tonic-gate ld->ld_responses->lm_next = lm->lm_next;
243*0Sstevel@tonic-gate } else {
244*0Sstevel@tonic-gate lastlm->lm_next = lm->lm_chain;
245*0Sstevel@tonic-gate lastlm->lm_next->lm_next = lm->lm_next;
246*0Sstevel@tonic-gate }
247*0Sstevel@tonic-gate }
248*0Sstevel@tonic-gate } else {
249*0Sstevel@tonic-gate if ( lastlm == NULL ) {
250*0Sstevel@tonic-gate ld->ld_responses = lm->lm_next;
251*0Sstevel@tonic-gate } else {
252*0Sstevel@tonic-gate lastlm->lm_next = lm->lm_next;
253*0Sstevel@tonic-gate }
254*0Sstevel@tonic-gate }
255*0Sstevel@tonic-gate
256*0Sstevel@tonic-gate if ( all == 0 ) {
257*0Sstevel@tonic-gate lm->lm_chain = NULL;
258*0Sstevel@tonic-gate }
259*0Sstevel@tonic-gate lm->lm_next = NULL;
260*0Sstevel@tonic-gate LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
261*0Sstevel@tonic-gate
262*0Sstevel@tonic-gate *result = lm;
263*0Sstevel@tonic-gate LDAPDebug( LDAP_DEBUG_TRACE,
264*0Sstevel@tonic-gate "<= check_response_queue returning msgid %d type %d\n",
265*0Sstevel@tonic-gate lm->lm_msgid, lm->lm_msgtype, 0 );
266*0Sstevel@tonic-gate return( 1 ); /* a message was found and returned in *result */
267*0Sstevel@tonic-gate }
268*0Sstevel@tonic-gate
269*0Sstevel@tonic-gate
270*0Sstevel@tonic-gate static int
wait4msg(LDAP * ld,int msgid,int all,int unlock_permitted,struct timeval * timeout,LDAPMessage ** result)271*0Sstevel@tonic-gate wait4msg( LDAP *ld, int msgid, int all, int unlock_permitted,
272*0Sstevel@tonic-gate struct timeval *timeout, LDAPMessage **result )
273*0Sstevel@tonic-gate {
274*0Sstevel@tonic-gate int rc;
275*0Sstevel@tonic-gate struct timeval tv, *tvp;
276*0Sstevel@tonic-gate #ifdef _SOLARIS_SDK
277*0Sstevel@tonic-gate hrtime_t start_time = 0, tmp_time, tv_time;
278*0Sstevel@tonic-gate #else
279*0Sstevel@tonic-gate long start_time = 0, tmp_time;
280*0Sstevel@tonic-gate #endif
281*0Sstevel@tonic-gate LDAPConn *lc, *nextlc;
282*0Sstevel@tonic-gate LDAPRequest *lr;
283*0Sstevel@tonic-gate
284*0Sstevel@tonic-gate #ifdef LDAP_DEBUG
285*0Sstevel@tonic-gate if ( timeout == NULL ) {
286*0Sstevel@tonic-gate LDAPDebug( LDAP_DEBUG_TRACE, "wait4msg (infinite timeout)\n",
287*0Sstevel@tonic-gate 0, 0, 0 );
288*0Sstevel@tonic-gate } else {
289*0Sstevel@tonic-gate LDAPDebug( LDAP_DEBUG_TRACE, "wait4msg (timeout %ld sec, %ld usec)\n",
290*0Sstevel@tonic-gate timeout->tv_sec, timeout->tv_usec, 0 );
291*0Sstevel@tonic-gate }
292*0Sstevel@tonic-gate #endif /* LDAP_DEBUG */
293*0Sstevel@tonic-gate
294*0Sstevel@tonic-gate /* check the cache */
295*0Sstevel@tonic-gate if ( ld->ld_cache_on && ld->ld_cache_result != NULL ) {
296*0Sstevel@tonic-gate /* if ( unlock_permitted ) LDAP_MUTEX_UNLOCK( ld ); */
297*0Sstevel@tonic-gate LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK );
298*0Sstevel@tonic-gate rc = (ld->ld_cache_result)( ld, msgid, all, timeout, result );
299*0Sstevel@tonic-gate LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
300*0Sstevel@tonic-gate /* if ( unlock_permitted ) LDAP_MUTEX_LOCK( ld ); */
301*0Sstevel@tonic-gate if ( rc != 0 ) {
302*0Sstevel@tonic-gate return( rc );
303*0Sstevel@tonic-gate }
304*0Sstevel@tonic-gate if ( ld->ld_cache_strategy == LDAP_CACHE_LOCALDB ) {
305*0Sstevel@tonic-gate LDAP_SET_LDERRNO( ld, LDAP_TIMEOUT, NULL, NULL );
306*0Sstevel@tonic-gate return( 0 ); /* timeout */
307*0Sstevel@tonic-gate }
308*0Sstevel@tonic-gate }
309*0Sstevel@tonic-gate
310*0Sstevel@tonic-gate /*
311*0Sstevel@tonic-gate * if we are looking for a specific msgid, check to see if it is
312*0Sstevel@tonic-gate * associated with a dead connection and return an error if so.
313*0Sstevel@tonic-gate */
314*0Sstevel@tonic-gate if ( msgid != LDAP_RES_ANY && msgid != LDAP_RES_UNSOLICITED ) {
315*0Sstevel@tonic-gate LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
316*0Sstevel@tonic-gate if (( lr = nsldapi_find_request_by_msgid( ld, msgid ))
317*0Sstevel@tonic-gate == NULL ) {
318*0Sstevel@tonic-gate LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
319*0Sstevel@tonic-gate LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL,
320*0Sstevel@tonic-gate nsldapi_strdup( dgettext(TEXT_DOMAIN,
321*0Sstevel@tonic-gate "unknown message id") ));
322*0Sstevel@tonic-gate return( -1 ); /* could not find request for msgid */
323*0Sstevel@tonic-gate }
324*0Sstevel@tonic-gate if ( lr->lr_conn != NULL &&
325*0Sstevel@tonic-gate lr->lr_conn->lconn_status == LDAP_CONNST_DEAD ) {
326*0Sstevel@tonic-gate nsldapi_free_request( ld, lr, 1 );
327*0Sstevel@tonic-gate LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
328*0Sstevel@tonic-gate LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN, NULL, NULL );
329*0Sstevel@tonic-gate return( -1 ); /* connection dead */
330*0Sstevel@tonic-gate }
331*0Sstevel@tonic-gate LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
332*0Sstevel@tonic-gate }
333*0Sstevel@tonic-gate
334*0Sstevel@tonic-gate if ( timeout == NULL ) {
335*0Sstevel@tonic-gate tvp = NULL;
336*0Sstevel@tonic-gate } else {
337*0Sstevel@tonic-gate tv = *timeout;
338*0Sstevel@tonic-gate tvp = &tv;
339*0Sstevel@tonic-gate #ifdef _SOLARIS_SDK
340*0Sstevel@tonic-gate start_time = gethrtime();
341*0Sstevel@tonic-gate tv_time = ((hrtime_t)tv.tv_sec * NANOSEC +
342*0Sstevel@tonic-gate (hrtime_t)tv.tv_usec * (NANOSEC / MICROSEC));
343*0Sstevel@tonic-gate #else
344*0Sstevel@tonic-gate start_time = (long)time( NULL );
345*0Sstevel@tonic-gate #endif
346*0Sstevel@tonic-gate }
347*0Sstevel@tonic-gate
348*0Sstevel@tonic-gate rc = -2;
349*0Sstevel@tonic-gate while ( rc == -2 ) {
350*0Sstevel@tonic-gate #ifdef LDAP_DEBUG
351*0Sstevel@tonic-gate if ( ldap_debug & LDAP_DEBUG_TRACE ) {
352*0Sstevel@tonic-gate nsldapi_dump_connection( ld, ld->ld_conns, 1 );
353*0Sstevel@tonic-gate nsldapi_dump_requests_and_responses( ld );
354*0Sstevel@tonic-gate }
355*0Sstevel@tonic-gate #endif /* LDAP_DEBUG */
356*0Sstevel@tonic-gate LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK );
357*0Sstevel@tonic-gate LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
358*0Sstevel@tonic-gate for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {
359*0Sstevel@tonic-gate if ( lc->lconn_sb->sb_ber.ber_ptr <
360*0Sstevel@tonic-gate lc->lconn_sb->sb_ber.ber_end ) {
361*0Sstevel@tonic-gate rc = read1msg( ld, msgid, all, lc->lconn_sb,
362*0Sstevel@tonic-gate lc, result );
363*0Sstevel@tonic-gate break;
364*0Sstevel@tonic-gate }
365*0Sstevel@tonic-gate }
366*0Sstevel@tonic-gate LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
367*0Sstevel@tonic-gate LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
368*0Sstevel@tonic-gate
369*0Sstevel@tonic-gate if ( lc == NULL ) {
370*0Sstevel@tonic-gate rc = nsldapi_iostatus_poll( ld, tvp );
371*0Sstevel@tonic-gate
372*0Sstevel@tonic-gate #if defined( LDAP_DEBUG ) && !defined( macintosh ) && !defined( DOS )
373*0Sstevel@tonic-gate if ( rc == -1 ) {
374*0Sstevel@tonic-gate LDAPDebug( LDAP_DEBUG_TRACE,
375*0Sstevel@tonic-gate "nsldapi_iostatus_poll returned -1: errno %d\n",
376*0Sstevel@tonic-gate LDAP_GET_ERRNO( ld ), 0, 0 );
377*0Sstevel@tonic-gate }
378*0Sstevel@tonic-gate #endif
379*0Sstevel@tonic-gate
380*0Sstevel@tonic-gate #if !defined( macintosh ) && !defined( DOS )
381*0Sstevel@tonic-gate if ( rc == 0 || ( rc == -1 && (( ld->ld_options &
382*0Sstevel@tonic-gate LDAP_BITOPT_RESTART ) == 0 ||
383*0Sstevel@tonic-gate LDAP_GET_ERRNO( ld ) != EINTR ))) {
384*0Sstevel@tonic-gate #else
385*0Sstevel@tonic-gate if ( rc == -1 || rc == 0 ) {
386*0Sstevel@tonic-gate #endif
387*0Sstevel@tonic-gate LDAP_SET_LDERRNO( ld, (rc == -1 ?
388*0Sstevel@tonic-gate LDAP_SERVER_DOWN : LDAP_TIMEOUT), NULL,
389*0Sstevel@tonic-gate NULL );
390*0Sstevel@tonic-gate if ( rc == -1 ) {
391*0Sstevel@tonic-gate LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
392*0Sstevel@tonic-gate nsldapi_connection_lost_nolock( ld,
393*0Sstevel@tonic-gate NULL );
394*0Sstevel@tonic-gate LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
395*0Sstevel@tonic-gate }
396*0Sstevel@tonic-gate return( rc );
397*0Sstevel@tonic-gate }
398*0Sstevel@tonic-gate
399*0Sstevel@tonic-gate if ( rc == -1 ) {
400*0Sstevel@tonic-gate rc = -2; /* select interrupted: loop */
401*0Sstevel@tonic-gate } else {
402*0Sstevel@tonic-gate rc = -2;
403*0Sstevel@tonic-gate LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK );
404*0Sstevel@tonic-gate LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
405*0Sstevel@tonic-gate for ( lc = ld->ld_conns; rc == -2 && lc != NULL;
406*0Sstevel@tonic-gate lc = nextlc ) {
407*0Sstevel@tonic-gate nextlc = lc->lconn_next;
408*0Sstevel@tonic-gate if ( lc->lconn_status ==
409*0Sstevel@tonic-gate LDAP_CONNST_CONNECTED &&
410*0Sstevel@tonic-gate nsldapi_iostatus_is_read_ready( ld,
411*0Sstevel@tonic-gate lc->lconn_sb )) {
412*0Sstevel@tonic-gate rc = read1msg( ld, msgid, all,
413*0Sstevel@tonic-gate lc->lconn_sb, lc, result );
414*0Sstevel@tonic-gate }
415*0Sstevel@tonic-gate else if (ld->ld_options & LDAP_BITOPT_ASYNC) {
416*0Sstevel@tonic-gate if ( lr
417*0Sstevel@tonic-gate && lc->lconn_status == LDAP_CONNST_CONNECTING
418*0Sstevel@tonic-gate && nsldapi_iostatus_is_write_ready( ld,
419*0Sstevel@tonic-gate lc->lconn_sb ) ) {
420*0Sstevel@tonic-gate rc = nsldapi_ber_flush( ld, lc->lconn_sb, lr->lr_ber, 0, 1 );
421*0Sstevel@tonic-gate if ( rc == 0 ) {
422*0Sstevel@tonic-gate rc = LDAP_RES_BIND;
423*0Sstevel@tonic-gate lc->lconn_status = LDAP_CONNST_CONNECTED;
424*0Sstevel@tonic-gate
425*0Sstevel@tonic-gate lr->lr_ber->ber_end = lr->lr_ber->ber_ptr;
426*0Sstevel@tonic-gate lr->lr_ber->ber_ptr = lr->lr_ber->ber_buf;
427*0Sstevel@tonic-gate nsldapi_iostatus_interest_read( ld, lc->lconn_sb );
428*0Sstevel@tonic-gate }
429*0Sstevel@tonic-gate else if ( rc == -1 ) {
430*0Sstevel@tonic-gate LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN, NULL, NULL );
431*0Sstevel@tonic-gate nsldapi_free_request( ld, lr, 0 );
432*0Sstevel@tonic-gate nsldapi_free_connection( ld, lc, NULL, NULL,
433*0Sstevel@tonic-gate 0, 0 );
434*0Sstevel@tonic-gate }
435*0Sstevel@tonic-gate }
436*0Sstevel@tonic-gate
437*0Sstevel@tonic-gate }
438*0Sstevel@tonic-gate }
439*0Sstevel@tonic-gate LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
440*0Sstevel@tonic-gate LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
441*0Sstevel@tonic-gate }
442*0Sstevel@tonic-gate }
443*0Sstevel@tonic-gate
444*0Sstevel@tonic-gate /*
445*0Sstevel@tonic-gate * It is possible that recursion occurred while chasing
446*0Sstevel@tonic-gate * referrals and as a result the message we are looking
447*0Sstevel@tonic-gate * for may have been placed on the response queue. Look
448*0Sstevel@tonic-gate * for it there before continuing so we don't end up
449*0Sstevel@tonic-gate * waiting on the network for a message that we already
450*0Sstevel@tonic-gate * received!
451*0Sstevel@tonic-gate */
452*0Sstevel@tonic-gate if ( rc == -2 &&
453*0Sstevel@tonic-gate check_response_queue( ld, msgid, all, 0, result ) != 0 ) {
454*0Sstevel@tonic-gate LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, NULL );
455*0Sstevel@tonic-gate rc = (*result)->lm_msgtype;
456*0Sstevel@tonic-gate }
457*0Sstevel@tonic-gate
458*0Sstevel@tonic-gate /*
459*0Sstevel@tonic-gate * honor the timeout if specified
460*0Sstevel@tonic-gate */
461*0Sstevel@tonic-gate if ( rc == -2 && tvp != NULL ) {
462*0Sstevel@tonic-gate #ifdef _SOLARIS_SDK
463*0Sstevel@tonic-gate tmp_time = gethrtime();
464*0Sstevel@tonic-gate if ((tv_time -= (tmp_time - start_time)) <= 0) {
465*0Sstevel@tonic-gate #else
466*0Sstevel@tonic-gate tmp_time = (long)time( NULL );
467*0Sstevel@tonic-gate if (( tv.tv_sec -= ( tmp_time - start_time )) <= 0 ) {
468*0Sstevel@tonic-gate #endif
469*0Sstevel@tonic-gate rc = 0; /* timed out */
470*0Sstevel@tonic-gate LDAP_SET_LDERRNO( ld, LDAP_TIMEOUT, NULL,
471*0Sstevel@tonic-gate NULL );
472*0Sstevel@tonic-gate break;
473*0Sstevel@tonic-gate }
474*0Sstevel@tonic-gate
475*0Sstevel@tonic-gate #ifdef _SOLARIS_SDK
476*0Sstevel@tonic-gate tv.tv_sec = tv_time / NANOSEC;
477*0Sstevel@tonic-gate tv.tv_usec = (tv_time % NANOSEC) / (NANOSEC / MICROSEC);
478*0Sstevel@tonic-gate #endif
479*0Sstevel@tonic-gate LDAPDebug( LDAP_DEBUG_TRACE, "wait4msg: %ld secs to go\n",
480*0Sstevel@tonic-gate tv.tv_sec, 0, 0 );
481*0Sstevel@tonic-gate start_time = tmp_time;
482*0Sstevel@tonic-gate }
483*0Sstevel@tonic-gate }
484*0Sstevel@tonic-gate
485*0Sstevel@tonic-gate return( rc );
486*0Sstevel@tonic-gate }
487*0Sstevel@tonic-gate
488*0Sstevel@tonic-gate
489*0Sstevel@tonic-gate /*
490*0Sstevel@tonic-gate * read1msg() should be called with LDAP_CONN_LOCK and LDAP_REQ_LOCK locked.
491*0Sstevel@tonic-gate */
492*0Sstevel@tonic-gate static int
493*0Sstevel@tonic-gate read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb, LDAPConn *lc,
494*0Sstevel@tonic-gate LDAPMessage **result )
495*0Sstevel@tonic-gate {
496*0Sstevel@tonic-gate BerElement *ber;
497*0Sstevel@tonic-gate LDAPMessage *new, *l, *prev, *chainprev, *tmp;
498*0Sstevel@tonic-gate ber_int_t id;
499*0Sstevel@tonic-gate ber_tag_t tag;
500*0Sstevel@tonic-gate ber_len_t len;
501*0Sstevel@tonic-gate int terrno, lderr, foundit = 0;
502*0Sstevel@tonic-gate LDAPRequest *lr;
503*0Sstevel@tonic-gate int rc, has_parent, message_can_be_returned;
504*0Sstevel@tonic-gate int manufactured_result = 0;
505*0Sstevel@tonic-gate
506*0Sstevel@tonic-gate LDAPDebug( LDAP_DEBUG_TRACE, "read1msg\n", 0, 0, 0 );
507*0Sstevel@tonic-gate
508*0Sstevel@tonic-gate message_can_be_returned = 1; /* the usual case... */
509*0Sstevel@tonic-gate
510*0Sstevel@tonic-gate /*
511*0Sstevel@tonic-gate * if we are not already in the midst of reading a message, allocate
512*0Sstevel@tonic-gate * a ber that is associated with this connection
513*0Sstevel@tonic-gate */
514*0Sstevel@tonic-gate if ( lc->lconn_ber == NULLBER && nsldapi_alloc_ber_with_options( ld,
515*0Sstevel@tonic-gate &lc->lconn_ber ) != LDAP_SUCCESS ) {
516*0Sstevel@tonic-gate return( -1 );
517*0Sstevel@tonic-gate }
518*0Sstevel@tonic-gate
519*0Sstevel@tonic-gate /*
520*0Sstevel@tonic-gate * ber_get_next() doesn't set errno on EOF, so we pre-set it to
521*0Sstevel@tonic-gate * zero to avoid getting tricked by leftover "EAGAIN" errors
522*0Sstevel@tonic-gate */
523*0Sstevel@tonic-gate LDAP_SET_ERRNO( ld, 0 );
524*0Sstevel@tonic-gate
525*0Sstevel@tonic-gate /* get the next message */
526*0Sstevel@tonic-gate if ( (tag = ber_get_next( sb, &len, lc->lconn_ber ))
527*0Sstevel@tonic-gate != LDAP_TAG_MESSAGE ) {
528*0Sstevel@tonic-gate terrno = LDAP_GET_ERRNO( ld );
529*0Sstevel@tonic-gate if ( terrno == EWOULDBLOCK || terrno == EAGAIN ) {
530*0Sstevel@tonic-gate return( -2 ); /* try again */
531*0Sstevel@tonic-gate }
532*0Sstevel@tonic-gate LDAP_SET_LDERRNO( ld, (tag == LBER_DEFAULT ? LDAP_SERVER_DOWN :
533*0Sstevel@tonic-gate LDAP_LOCAL_ERROR), NULL, NULL );
534*0Sstevel@tonic-gate if ( tag == LBER_DEFAULT ) {
535*0Sstevel@tonic-gate nsldapi_connection_lost_nolock( ld, sb );
536*0Sstevel@tonic-gate }
537*0Sstevel@tonic-gate return( -1 );
538*0Sstevel@tonic-gate }
539*0Sstevel@tonic-gate
540*0Sstevel@tonic-gate /*
541*0Sstevel@tonic-gate * Since we have received a complete message now, we pull this ber
542*0Sstevel@tonic-gate * out of the connection structure and never read into it again.
543*0Sstevel@tonic-gate */
544*0Sstevel@tonic-gate ber = lc->lconn_ber;
545*0Sstevel@tonic-gate lc->lconn_ber = NULLBER;
546*0Sstevel@tonic-gate
547*0Sstevel@tonic-gate /* message id */
548*0Sstevel@tonic-gate if ( ber_get_int( ber, &id ) == LBER_ERROR ) {
549*0Sstevel@tonic-gate LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
550*0Sstevel@tonic-gate return( -1 );
551*0Sstevel@tonic-gate }
552*0Sstevel@tonic-gate
553*0Sstevel@tonic-gate /* if it's been abandoned, toss it */
554*0Sstevel@tonic-gate if ( ldap_abandoned( ld, (int)id ) ) {
555*0Sstevel@tonic-gate ber_free( ber, 1 );
556*0Sstevel@tonic-gate return( -2 ); /* continue looking */
557*0Sstevel@tonic-gate }
558*0Sstevel@tonic-gate
559*0Sstevel@tonic-gate if ( id == LDAP_RES_UNSOLICITED ) {
560*0Sstevel@tonic-gate lr = NULL;
561*0Sstevel@tonic-gate } else if (( lr = nsldapi_find_request_by_msgid( ld, id )) == NULL ) {
562*0Sstevel@tonic-gate LDAPDebug( LDAP_DEBUG_ANY,
563*0Sstevel@tonic-gate "no request for response with msgid %ld (tossing)\n",
564*0Sstevel@tonic-gate id, 0, 0 );
565*0Sstevel@tonic-gate ber_free( ber, 1 );
566*0Sstevel@tonic-gate return( -2 ); /* continue looking */
567*0Sstevel@tonic-gate }
568*0Sstevel@tonic-gate
569*0Sstevel@tonic-gate /* the message type */
570*0Sstevel@tonic-gate if ( (tag = ber_peek_tag( ber, &len )) == LBER_ERROR ) {
571*0Sstevel@tonic-gate LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
572*0Sstevel@tonic-gate return( -1 );
573*0Sstevel@tonic-gate }
574*0Sstevel@tonic-gate LDAPDebug( LDAP_DEBUG_TRACE, "got %s msgid %ld, original id %d\n",
575*0Sstevel@tonic-gate ( tag == LDAP_RES_SEARCH_ENTRY ) ? "ENTRY" :
576*0Sstevel@tonic-gate ( tag == LDAP_RES_SEARCH_REFERENCE ) ? "REFERENCE" : "RESULT", id,
577*0Sstevel@tonic-gate ( lr == NULL ) ? id : lr->lr_origid );
578*0Sstevel@tonic-gate
579*0Sstevel@tonic-gate if ( lr != NULL ) {
580*0Sstevel@tonic-gate id = lr->lr_origid;
581*0Sstevel@tonic-gate lr->lr_res_msgtype = tag;
582*0Sstevel@tonic-gate }
583*0Sstevel@tonic-gate rc = -2; /* default is to keep looking (no response found) */
584*0Sstevel@tonic-gate
585*0Sstevel@tonic-gate if ( id != LDAP_RES_UNSOLICITED && ( tag == LDAP_RES_SEARCH_REFERENCE ||
586*0Sstevel@tonic-gate tag != LDAP_RES_SEARCH_ENTRY )) {
587*0Sstevel@tonic-gate int refchasing, reftotal, simple_request = 0;
588*0Sstevel@tonic-gate
589*0Sstevel@tonic-gate check_for_refs( ld, lr, ber, lc->lconn_version, &reftotal,
590*0Sstevel@tonic-gate &refchasing );
591*0Sstevel@tonic-gate
592*0Sstevel@tonic-gate if ( refchasing > 0 || lr->lr_outrefcnt > 0 ) {
593*0Sstevel@tonic-gate /*
594*0Sstevel@tonic-gate * we're chasing one or more new refs...
595*0Sstevel@tonic-gate */
596*0Sstevel@tonic-gate ber_free( ber, 1 );
597*0Sstevel@tonic-gate ber = NULLBER;
598*0Sstevel@tonic-gate lr->lr_status = LDAP_REQST_CHASINGREFS;
599*0Sstevel@tonic-gate message_can_be_returned = 0;
600*0Sstevel@tonic-gate
601*0Sstevel@tonic-gate } else if ( tag != LDAP_RES_SEARCH_REFERENCE ) {
602*0Sstevel@tonic-gate /*
603*0Sstevel@tonic-gate * this request is complete...
604*0Sstevel@tonic-gate */
605*0Sstevel@tonic-gate has_parent = ( lr->lr_parent != NULL );
606*0Sstevel@tonic-gate
607*0Sstevel@tonic-gate if ( lr->lr_outrefcnt <= 0 && !has_parent ) {
608*0Sstevel@tonic-gate /* request without any refs */
609*0Sstevel@tonic-gate simple_request = ( reftotal == 0 );
610*0Sstevel@tonic-gate }
611*0Sstevel@tonic-gate
612*0Sstevel@tonic-gate /*
613*0Sstevel@tonic-gate * If this is not a child request and it is a bind
614*0Sstevel@tonic-gate * request, reset the connection's bind DN and
615*0Sstevel@tonic-gate * status based on the result of the operation.
616*0Sstevel@tonic-gate */
617*0Sstevel@tonic-gate if ( !has_parent &&
618*0Sstevel@tonic-gate LDAP_RES_BIND == lr->lr_res_msgtype &&
619*0Sstevel@tonic-gate lr->lr_conn != NULL ) {
620*0Sstevel@tonic-gate if ( lr->lr_conn->lconn_binddn != NULL ) {
621*0Sstevel@tonic-gate NSLDAPI_FREE(
622*0Sstevel@tonic-gate lr->lr_conn->lconn_binddn );
623*0Sstevel@tonic-gate }
624*0Sstevel@tonic-gate if ( LDAP_SUCCESS == nsldapi_parse_result( ld,
625*0Sstevel@tonic-gate lr->lr_res_msgtype, ber, &lderr, NULL,
626*0Sstevel@tonic-gate NULL, NULL, NULL )
627*0Sstevel@tonic-gate && LDAP_SUCCESS == lderr ) {
628*0Sstevel@tonic-gate lr->lr_conn->lconn_bound = 1;
629*0Sstevel@tonic-gate lr->lr_conn->lconn_binddn =
630*0Sstevel@tonic-gate lr->lr_binddn;
631*0Sstevel@tonic-gate lr->lr_binddn = NULL;
632*0Sstevel@tonic-gate } else {
633*0Sstevel@tonic-gate lr->lr_conn->lconn_bound = 0;
634*0Sstevel@tonic-gate lr->lr_conn->lconn_binddn = NULL;
635*0Sstevel@tonic-gate }
636*0Sstevel@tonic-gate }
637*0Sstevel@tonic-gate
638*0Sstevel@tonic-gate /*
639*0Sstevel@tonic-gate * if this response is to a child request, we toss
640*0Sstevel@tonic-gate * the message contents and just merge error info.
641*0Sstevel@tonic-gate * into the parent.
642*0Sstevel@tonic-gate */
643*0Sstevel@tonic-gate if ( has_parent ) {
644*0Sstevel@tonic-gate ber_free( ber, 1 );
645*0Sstevel@tonic-gate ber = NULLBER;
646*0Sstevel@tonic-gate }
647*0Sstevel@tonic-gate while ( lr->lr_parent != NULL ) {
648*0Sstevel@tonic-gate merge_error_info( ld, lr->lr_parent, lr );
649*0Sstevel@tonic-gate
650*0Sstevel@tonic-gate lr = lr->lr_parent;
651*0Sstevel@tonic-gate if ( --lr->lr_outrefcnt > 0 ) {
652*0Sstevel@tonic-gate break; /* not completely done yet */
653*0Sstevel@tonic-gate }
654*0Sstevel@tonic-gate }
655*0Sstevel@tonic-gate
656*0Sstevel@tonic-gate /*
657*0Sstevel@tonic-gate * we recognize a request as complete when:
658*0Sstevel@tonic-gate * 1) it has no outstanding referrals
659*0Sstevel@tonic-gate * 2) it is not a child request
660*0Sstevel@tonic-gate * 3) we have received a result for the request (i.e.,
661*0Sstevel@tonic-gate * something other than an entry or a reference).
662*0Sstevel@tonic-gate */
663*0Sstevel@tonic-gate if ( lr->lr_outrefcnt <= 0 && lr->lr_parent == NULL &&
664*0Sstevel@tonic-gate lr->lr_res_msgtype != LDAP_RES_SEARCH_ENTRY &&
665*0Sstevel@tonic-gate lr->lr_res_msgtype != LDAP_RES_SEARCH_REFERENCE ) {
666*0Sstevel@tonic-gate id = lr->lr_msgid;
667*0Sstevel@tonic-gate tag = lr->lr_res_msgtype;
668*0Sstevel@tonic-gate LDAPDebug( LDAP_DEBUG_TRACE,
669*0Sstevel@tonic-gate "request %ld done\n", id, 0, 0 );
670*0Sstevel@tonic-gate LDAPDebug( LDAP_DEBUG_TRACE,
671*0Sstevel@tonic-gate "res_errno: %d, res_error: <%s>, res_matched: <%s>\n",
672*0Sstevel@tonic-gate lr->lr_res_errno, lr->lr_res_error ? lr->lr_res_error : "",
673*0Sstevel@tonic-gate lr->lr_res_matched ? lr->lr_res_matched : "" );
674*0Sstevel@tonic-gate if ( !simple_request ) {
675*0Sstevel@tonic-gate if ( ber != NULLBER ) {
676*0Sstevel@tonic-gate ber_free( ber, 1 );
677*0Sstevel@tonic-gate ber = NULLBER;
678*0Sstevel@tonic-gate }
679*0Sstevel@tonic-gate if ( build_result_ber( ld, &ber, lr )
680*0Sstevel@tonic-gate != LDAP_SUCCESS ) {
681*0Sstevel@tonic-gate rc = -1; /* fatal error */
682*0Sstevel@tonic-gate } else {
683*0Sstevel@tonic-gate manufactured_result = 1;
684*0Sstevel@tonic-gate }
685*0Sstevel@tonic-gate }
686*0Sstevel@tonic-gate
687*0Sstevel@tonic-gate nsldapi_free_request( ld, lr, 1 );
688*0Sstevel@tonic-gate } else {
689*0Sstevel@tonic-gate message_can_be_returned = 0;
690*0Sstevel@tonic-gate }
691*0Sstevel@tonic-gate }
692*0Sstevel@tonic-gate }
693*0Sstevel@tonic-gate
694*0Sstevel@tonic-gate if ( ber == NULLBER ) {
695*0Sstevel@tonic-gate return( rc );
696*0Sstevel@tonic-gate }
697*0Sstevel@tonic-gate
698*0Sstevel@tonic-gate /* make a new ldap message */
699*0Sstevel@tonic-gate if ( (new = (LDAPMessage*)NSLDAPI_CALLOC( 1, sizeof(struct ldapmsg) ))
700*0Sstevel@tonic-gate == NULL ) {
701*0Sstevel@tonic-gate LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
702*0Sstevel@tonic-gate return( -1 );
703*0Sstevel@tonic-gate }
704*0Sstevel@tonic-gate new->lm_msgid = (int)id;
705*0Sstevel@tonic-gate new->lm_msgtype = tag;
706*0Sstevel@tonic-gate new->lm_ber = ber;
707*0Sstevel@tonic-gate
708*0Sstevel@tonic-gate /*
709*0Sstevel@tonic-gate * if this is a search entry or if this request is complete (i.e.,
710*0Sstevel@tonic-gate * there are no outstanding referrals) then add to cache and check
711*0Sstevel@tonic-gate * to see if we should return this to the caller right away or not.
712*0Sstevel@tonic-gate */
713*0Sstevel@tonic-gate if ( message_can_be_returned ) {
714*0Sstevel@tonic-gate if ( ld->ld_cache_on ) {
715*0Sstevel@tonic-gate nsldapi_add_result_to_cache( ld, new );
716*0Sstevel@tonic-gate }
717*0Sstevel@tonic-gate
718*0Sstevel@tonic-gate if ( msgid == LDAP_RES_ANY || id == msgid ) {
719*0Sstevel@tonic-gate if ( new->lm_msgtype == LDAP_RES_SEARCH_RESULT ) {
720*0Sstevel@tonic-gate /*
721*0Sstevel@tonic-gate * return the first response we have for this
722*0Sstevel@tonic-gate * search request later (possibly an entire
723*0Sstevel@tonic-gate * chain of messages).
724*0Sstevel@tonic-gate */
725*0Sstevel@tonic-gate foundit = 1;
726*0Sstevel@tonic-gate } else if ( all == 0
727*0Sstevel@tonic-gate || (new->lm_msgtype != LDAP_RES_SEARCH_REFERENCE
728*0Sstevel@tonic-gate && new->lm_msgtype != LDAP_RES_SEARCH_ENTRY) ) {
729*0Sstevel@tonic-gate *result = new;
730*0Sstevel@tonic-gate LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL,
731*0Sstevel@tonic-gate NULL );
732*0Sstevel@tonic-gate return( tag );
733*0Sstevel@tonic-gate }
734*0Sstevel@tonic-gate }
735*0Sstevel@tonic-gate }
736*0Sstevel@tonic-gate
737*0Sstevel@tonic-gate /*
738*0Sstevel@tonic-gate * if not, we must add it to the list of responses. if
739*0Sstevel@tonic-gate * the msgid is already there, it must be part of an existing
740*0Sstevel@tonic-gate * search response.
741*0Sstevel@tonic-gate */
742*0Sstevel@tonic-gate
743*0Sstevel@tonic-gate prev = NULL;
744*0Sstevel@tonic-gate LDAP_MUTEX_LOCK( ld, LDAP_RESP_LOCK );
745*0Sstevel@tonic-gate for ( l = ld->ld_responses; l != NULL; l = l->lm_next ) {
746*0Sstevel@tonic-gate if ( l->lm_msgid == new->lm_msgid )
747*0Sstevel@tonic-gate break;
748*0Sstevel@tonic-gate prev = l;
749*0Sstevel@tonic-gate }
750*0Sstevel@tonic-gate
751*0Sstevel@tonic-gate /* not part of an existing search response */
752*0Sstevel@tonic-gate if ( l == NULL ) {
753*0Sstevel@tonic-gate if ( foundit ) {
754*0Sstevel@tonic-gate LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
755*0Sstevel@tonic-gate *result = new;
756*0Sstevel@tonic-gate LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, NULL );
757*0Sstevel@tonic-gate return( tag );
758*0Sstevel@tonic-gate }
759*0Sstevel@tonic-gate
760*0Sstevel@tonic-gate new->lm_next = ld->ld_responses;
761*0Sstevel@tonic-gate ld->ld_responses = new;
762*0Sstevel@tonic-gate LDAPDebug( LDAP_DEBUG_TRACE,
763*0Sstevel@tonic-gate "adding new response id %d type %d (looking for id %d)\n",
764*0Sstevel@tonic-gate new->lm_msgid, new->lm_msgtype, msgid );
765*0Sstevel@tonic-gate LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
766*0Sstevel@tonic-gate if( message_can_be_returned )
767*0Sstevel@tonic-gate POST( ld, new->lm_msgid, new );
768*0Sstevel@tonic-gate return( -2 ); /* continue looking */
769*0Sstevel@tonic-gate }
770*0Sstevel@tonic-gate
771*0Sstevel@tonic-gate LDAPDebug( LDAP_DEBUG_TRACE,
772*0Sstevel@tonic-gate "adding response id %d type %d (looking for id %d)\n",
773*0Sstevel@tonic-gate new->lm_msgid, new->lm_msgtype, msgid );
774*0Sstevel@tonic-gate
775*0Sstevel@tonic-gate /*
776*0Sstevel@tonic-gate * part of a search response - add to end of list of entries
777*0Sstevel@tonic-gate *
778*0Sstevel@tonic-gate * the first step is to find the end of the list of entries and
779*0Sstevel@tonic-gate * references. after the following loop is executed, tmp points to
780*0Sstevel@tonic-gate * the last entry or reference in the chain. If there are none,
781*0Sstevel@tonic-gate * tmp points to the search result.
782*0Sstevel@tonic-gate */
783*0Sstevel@tonic-gate chainprev = NULL;
784*0Sstevel@tonic-gate for ( tmp = l; tmp->lm_chain != NULL &&
785*0Sstevel@tonic-gate ( tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_ENTRY
786*0Sstevel@tonic-gate || tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_REFERENCE );
787*0Sstevel@tonic-gate tmp = tmp->lm_chain ) {
788*0Sstevel@tonic-gate chainprev = tmp;
789*0Sstevel@tonic-gate }
790*0Sstevel@tonic-gate
791*0Sstevel@tonic-gate /*
792*0Sstevel@tonic-gate * If this is a manufactured result message and a result is already
793*0Sstevel@tonic-gate * queued we throw away the one that is queued and replace it with
794*0Sstevel@tonic-gate * our new result. This is necessary so we don't end up returning
795*0Sstevel@tonic-gate * more than one result.
796*0Sstevel@tonic-gate */
797*0Sstevel@tonic-gate if ( manufactured_result &&
798*0Sstevel@tonic-gate tmp->lm_msgtype == LDAP_RES_SEARCH_RESULT ) {
799*0Sstevel@tonic-gate /*
800*0Sstevel@tonic-gate * the result is the only thing in the chain... replace it.
801*0Sstevel@tonic-gate */
802*0Sstevel@tonic-gate new->lm_chain = tmp->lm_chain;
803*0Sstevel@tonic-gate new->lm_next = tmp->lm_next;
804*0Sstevel@tonic-gate if ( chainprev == NULL ) {
805*0Sstevel@tonic-gate if ( prev == NULL ) {
806*0Sstevel@tonic-gate ld->ld_responses = new;
807*0Sstevel@tonic-gate } else {
808*0Sstevel@tonic-gate prev->lm_next = new;
809*0Sstevel@tonic-gate }
810*0Sstevel@tonic-gate } else {
811*0Sstevel@tonic-gate chainprev->lm_chain = new;
812*0Sstevel@tonic-gate }
813*0Sstevel@tonic-gate if ( l == tmp ) {
814*0Sstevel@tonic-gate l = new;
815*0Sstevel@tonic-gate }
816*0Sstevel@tonic-gate ldap_msgfree( tmp );
817*0Sstevel@tonic-gate
818*0Sstevel@tonic-gate } else if ( manufactured_result && tmp->lm_chain != NULL
819*0Sstevel@tonic-gate && tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_RESULT ) {
820*0Sstevel@tonic-gate /*
821*0Sstevel@tonic-gate * entries or references are also present, so the result
822*0Sstevel@tonic-gate * is the next entry after tmp. replace it.
823*0Sstevel@tonic-gate */
824*0Sstevel@tonic-gate new->lm_chain = tmp->lm_chain->lm_chain;
825*0Sstevel@tonic-gate new->lm_next = tmp->lm_chain->lm_next;
826*0Sstevel@tonic-gate ldap_msgfree( tmp->lm_chain );
827*0Sstevel@tonic-gate tmp->lm_chain = new;
828*0Sstevel@tonic-gate
829*0Sstevel@tonic-gate } else if ( tmp->lm_msgtype == LDAP_RES_SEARCH_RESULT ) {
830*0Sstevel@tonic-gate /*
831*0Sstevel@tonic-gate * the result is the only thing in the chain... add before it.
832*0Sstevel@tonic-gate */
833*0Sstevel@tonic-gate new->lm_chain = tmp;
834*0Sstevel@tonic-gate if ( chainprev == NULL ) {
835*0Sstevel@tonic-gate if ( prev == NULL ) {
836*0Sstevel@tonic-gate ld->ld_responses = new;
837*0Sstevel@tonic-gate } else {
838*0Sstevel@tonic-gate prev->lm_next = new;
839*0Sstevel@tonic-gate }
840*0Sstevel@tonic-gate } else {
841*0Sstevel@tonic-gate chainprev->lm_chain = new;
842*0Sstevel@tonic-gate }
843*0Sstevel@tonic-gate if ( l == tmp ) {
844*0Sstevel@tonic-gate l = new;
845*0Sstevel@tonic-gate }
846*0Sstevel@tonic-gate
847*0Sstevel@tonic-gate } else {
848*0Sstevel@tonic-gate /*
849*0Sstevel@tonic-gate * entries and/or references are present... add to the end
850*0Sstevel@tonic-gate * of the entry/reference part of the chain.
851*0Sstevel@tonic-gate */
852*0Sstevel@tonic-gate new->lm_chain = tmp->lm_chain;
853*0Sstevel@tonic-gate tmp->lm_chain = new;
854*0Sstevel@tonic-gate }
855*0Sstevel@tonic-gate
856*0Sstevel@tonic-gate /*
857*0Sstevel@tonic-gate * return the first response or the whole chain if that's what
858*0Sstevel@tonic-gate * we were looking for....
859*0Sstevel@tonic-gate */
860*0Sstevel@tonic-gate if ( foundit ) {
861*0Sstevel@tonic-gate if ( all == 0 && l->lm_chain != NULL ) {
862*0Sstevel@tonic-gate /*
863*0Sstevel@tonic-gate * only return the first response in the chain
864*0Sstevel@tonic-gate */
865*0Sstevel@tonic-gate if ( prev == NULL ) {
866*0Sstevel@tonic-gate ld->ld_responses = l->lm_chain;
867*0Sstevel@tonic-gate } else {
868*0Sstevel@tonic-gate prev->lm_next = l->lm_chain;
869*0Sstevel@tonic-gate }
870*0Sstevel@tonic-gate l->lm_chain = NULL;
871*0Sstevel@tonic-gate tag = l->lm_msgtype;
872*0Sstevel@tonic-gate } else {
873*0Sstevel@tonic-gate /*
874*0Sstevel@tonic-gate * return all of the responses (may be a chain)
875*0Sstevel@tonic-gate */
876*0Sstevel@tonic-gate if ( prev == NULL ) {
877*0Sstevel@tonic-gate ld->ld_responses = l->lm_next;
878*0Sstevel@tonic-gate } else {
879*0Sstevel@tonic-gate prev->lm_next = l->lm_next;
880*0Sstevel@tonic-gate }
881*0Sstevel@tonic-gate }
882*0Sstevel@tonic-gate *result = l;
883*0Sstevel@tonic-gate LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
884*0Sstevel@tonic-gate LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, NULL );
885*0Sstevel@tonic-gate return( tag );
886*0Sstevel@tonic-gate }
887*0Sstevel@tonic-gate LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
888*0Sstevel@tonic-gate return( -2 ); /* continue looking */
889*0Sstevel@tonic-gate }
890*0Sstevel@tonic-gate
891*0Sstevel@tonic-gate
892*0Sstevel@tonic-gate /*
893*0Sstevel@tonic-gate * check for LDAPv2+ (UMich extension) or LDAPv3 referrals or references
894*0Sstevel@tonic-gate * errors are merged in "lr".
895*0Sstevel@tonic-gate */
896*0Sstevel@tonic-gate static void
897*0Sstevel@tonic-gate check_for_refs( LDAP *ld, LDAPRequest *lr, BerElement *ber,
898*0Sstevel@tonic-gate int ldapversion, int *totalcountp, int *chasingcountp )
899*0Sstevel@tonic-gate {
900*0Sstevel@tonic-gate int err, origerr;
901*0Sstevel@tonic-gate char *errstr, *matcheddn, **v3refs;
902*0Sstevel@tonic-gate
903*0Sstevel@tonic-gate LDAPDebug( LDAP_DEBUG_TRACE, "check_for_refs\n", 0, 0, 0 );
904*0Sstevel@tonic-gate
905*0Sstevel@tonic-gate *chasingcountp = *totalcountp = 0;
906*0Sstevel@tonic-gate
907*0Sstevel@tonic-gate if ( ldapversion < LDAP_VERSION2 || ( lr->lr_parent == NULL
908*0Sstevel@tonic-gate && ( ld->ld_options & LDAP_BITOPT_REFERRALS ) == 0 )) {
909*0Sstevel@tonic-gate /* referrals are not supported or are disabled */
910*0Sstevel@tonic-gate return;
911*0Sstevel@tonic-gate }
912*0Sstevel@tonic-gate
913*0Sstevel@tonic-gate if ( lr->lr_res_msgtype == LDAP_RES_SEARCH_REFERENCE ) {
914*0Sstevel@tonic-gate err = nsldapi_parse_reference( ld, ber, &v3refs, NULL );
915*0Sstevel@tonic-gate origerr = LDAP_REFERRAL; /* a small lie... */
916*0Sstevel@tonic-gate matcheddn = errstr = NULL;
917*0Sstevel@tonic-gate } else {
918*0Sstevel@tonic-gate err = nsldapi_parse_result( ld, lr->lr_res_msgtype, ber,
919*0Sstevel@tonic-gate &origerr, &matcheddn, &errstr, &v3refs, NULL );
920*0Sstevel@tonic-gate }
921*0Sstevel@tonic-gate
922*0Sstevel@tonic-gate if ( err != LDAP_SUCCESS ) {
923*0Sstevel@tonic-gate /* parse failed */
924*0Sstevel@tonic-gate return;
925*0Sstevel@tonic-gate }
926*0Sstevel@tonic-gate
927*0Sstevel@tonic-gate if ( origerr == LDAP_REFERRAL ) { /* ldapv3 */
928*0Sstevel@tonic-gate if ( v3refs != NULL ) {
929*0Sstevel@tonic-gate err = nsldapi_chase_v3_refs( ld, lr, v3refs,
930*0Sstevel@tonic-gate ( lr->lr_res_msgtype == LDAP_RES_SEARCH_REFERENCE ),
931*0Sstevel@tonic-gate totalcountp, chasingcountp );
932*0Sstevel@tonic-gate ldap_value_free( v3refs );
933*0Sstevel@tonic-gate }
934*0Sstevel@tonic-gate } else if ( ldapversion == LDAP_VERSION2
935*0Sstevel@tonic-gate && origerr != LDAP_SUCCESS ) {
936*0Sstevel@tonic-gate /* referrals may be present in the error string */
937*0Sstevel@tonic-gate err = nsldapi_chase_v2_referrals( ld, lr, &errstr,
938*0Sstevel@tonic-gate totalcountp, chasingcountp );
939*0Sstevel@tonic-gate }
940*0Sstevel@tonic-gate
941*0Sstevel@tonic-gate /* set LDAP errno, message, and matched string appropriately */
942*0Sstevel@tonic-gate if ( lr->lr_res_error != NULL ) {
943*0Sstevel@tonic-gate NSLDAPI_FREE( lr->lr_res_error );
944*0Sstevel@tonic-gate }
945*0Sstevel@tonic-gate lr->lr_res_error = errstr;
946*0Sstevel@tonic-gate
947*0Sstevel@tonic-gate if ( lr->lr_res_matched != NULL ) {
948*0Sstevel@tonic-gate NSLDAPI_FREE( lr->lr_res_matched );
949*0Sstevel@tonic-gate }
950*0Sstevel@tonic-gate lr->lr_res_matched = matcheddn;
951*0Sstevel@tonic-gate
952*0Sstevel@tonic-gate if ( err == LDAP_SUCCESS && ( *chasingcountp == *totalcountp )) {
953*0Sstevel@tonic-gate if ( *totalcountp > 0 && ( origerr == LDAP_PARTIAL_RESULTS
954*0Sstevel@tonic-gate || origerr == LDAP_REFERRAL )) {
955*0Sstevel@tonic-gate /* substitute success for referral error codes */
956*0Sstevel@tonic-gate lr->lr_res_errno = LDAP_SUCCESS;
957*0Sstevel@tonic-gate } else {
958*0Sstevel@tonic-gate /* preserve existing non-referral error code */
959*0Sstevel@tonic-gate lr->lr_res_errno = origerr;
960*0Sstevel@tonic-gate }
961*0Sstevel@tonic-gate } else if ( err != LDAP_SUCCESS ) {
962*0Sstevel@tonic-gate /* error occurred while trying to chase referrals */
963*0Sstevel@tonic-gate lr->lr_res_errno = err;
964*0Sstevel@tonic-gate } else {
965*0Sstevel@tonic-gate /* some referrals were not recognized */
966*0Sstevel@tonic-gate lr->lr_res_errno = ( ldapversion == LDAP_VERSION2 )
967*0Sstevel@tonic-gate ? LDAP_PARTIAL_RESULTS : LDAP_REFERRAL;
968*0Sstevel@tonic-gate }
969*0Sstevel@tonic-gate
970*0Sstevel@tonic-gate LDAPDebug( LDAP_DEBUG_TRACE,
971*0Sstevel@tonic-gate "check_for_refs: new result: msgid %d, res_errno %d, ",
972*0Sstevel@tonic-gate lr->lr_msgid, lr->lr_res_errno, 0 );
973*0Sstevel@tonic-gate LDAPDebug( LDAP_DEBUG_TRACE, " res_error <%s>, res_matched <%s>\n",
974*0Sstevel@tonic-gate lr->lr_res_error ? lr->lr_res_error : "",
975*0Sstevel@tonic-gate lr->lr_res_matched ? lr->lr_res_matched : "", 0 );
976*0Sstevel@tonic-gate LDAPDebug( LDAP_DEBUG_TRACE,
977*0Sstevel@tonic-gate "check_for_refs: %d new refs(s); chasing %d of them\n",
978*0Sstevel@tonic-gate *totalcountp, *chasingcountp, 0 );
979*0Sstevel@tonic-gate }
980*0Sstevel@tonic-gate
981*0Sstevel@tonic-gate
982*0Sstevel@tonic-gate /* returns an LDAP error code and also sets it in LDAP * */
983*0Sstevel@tonic-gate static int
984*0Sstevel@tonic-gate build_result_ber( LDAP *ld, BerElement **berp, LDAPRequest *lr )
985*0Sstevel@tonic-gate {
986*0Sstevel@tonic-gate ber_len_t len;
987*0Sstevel@tonic-gate ber_int_t along;
988*0Sstevel@tonic-gate BerElement *ber;
989*0Sstevel@tonic-gate int err;
990*0Sstevel@tonic-gate
991*0Sstevel@tonic-gate if (( err = nsldapi_alloc_ber_with_options( ld, &ber ))
992*0Sstevel@tonic-gate != LDAP_SUCCESS ) {
993*0Sstevel@tonic-gate return( err );
994*0Sstevel@tonic-gate }
995*0Sstevel@tonic-gate *berp = ber;
996*0Sstevel@tonic-gate if ( ber_printf( ber, "{it{ess}}", lr->lr_msgid,
997*0Sstevel@tonic-gate (long)lr->lr_res_msgtype, lr->lr_res_errno,
998*0Sstevel@tonic-gate lr->lr_res_matched ? lr->lr_res_matched : "",
999*0Sstevel@tonic-gate lr->lr_res_error ? lr->lr_res_error : "" ) == -1 ) {
1000*0Sstevel@tonic-gate return( LDAP_ENCODING_ERROR );
1001*0Sstevel@tonic-gate }
1002*0Sstevel@tonic-gate
1003*0Sstevel@tonic-gate ber_reset( ber, 1 );
1004*0Sstevel@tonic-gate if ( ber_skip_tag( ber, &len ) == LBER_ERROR ||
1005*0Sstevel@tonic-gate ber_get_int( ber, &along ) == LBER_ERROR ||
1006*0Sstevel@tonic-gate ber_peek_tag( ber, &len ) == LBER_ERROR ) {
1007*0Sstevel@tonic-gate return( LDAP_DECODING_ERROR );
1008*0Sstevel@tonic-gate }
1009*0Sstevel@tonic-gate
1010*0Sstevel@tonic-gate return( LDAP_SUCCESS );
1011*0Sstevel@tonic-gate }
1012*0Sstevel@tonic-gate
1013*0Sstevel@tonic-gate
1014*0Sstevel@tonic-gate static void
1015*0Sstevel@tonic-gate merge_error_info( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr )
1016*0Sstevel@tonic-gate {
1017*0Sstevel@tonic-gate /*
1018*0Sstevel@tonic-gate * Merge error information in "lr" with "parentr" error code and string.
1019*0Sstevel@tonic-gate */
1020*0Sstevel@tonic-gate if ( lr->lr_res_errno == LDAP_PARTIAL_RESULTS ) {
1021*0Sstevel@tonic-gate parentr->lr_res_errno = lr->lr_res_errno;
1022*0Sstevel@tonic-gate if ( lr->lr_res_error != NULL ) {
1023*0Sstevel@tonic-gate (void)nsldapi_append_referral( ld, &parentr->lr_res_error,
1024*0Sstevel@tonic-gate lr->lr_res_error );
1025*0Sstevel@tonic-gate }
1026*0Sstevel@tonic-gate } else if ( lr->lr_res_errno != LDAP_SUCCESS &&
1027*0Sstevel@tonic-gate parentr->lr_res_errno == LDAP_SUCCESS ) {
1028*0Sstevel@tonic-gate parentr->lr_res_errno = lr->lr_res_errno;
1029*0Sstevel@tonic-gate if ( parentr->lr_res_error != NULL ) {
1030*0Sstevel@tonic-gate NSLDAPI_FREE( parentr->lr_res_error );
1031*0Sstevel@tonic-gate }
1032*0Sstevel@tonic-gate parentr->lr_res_error = lr->lr_res_error;
1033*0Sstevel@tonic-gate lr->lr_res_error = NULL;
1034*0Sstevel@tonic-gate if ( NAME_ERROR( lr->lr_res_errno )) {
1035*0Sstevel@tonic-gate if ( parentr->lr_res_matched != NULL ) {
1036*0Sstevel@tonic-gate NSLDAPI_FREE( parentr->lr_res_matched );
1037*0Sstevel@tonic-gate }
1038*0Sstevel@tonic-gate parentr->lr_res_matched = lr->lr_res_matched;
1039*0Sstevel@tonic-gate lr->lr_res_matched = NULL;
1040*0Sstevel@tonic-gate }
1041*0Sstevel@tonic-gate }
1042*0Sstevel@tonic-gate
1043*0Sstevel@tonic-gate LDAPDebug( LDAP_DEBUG_TRACE, "merged parent (id %d) error info: ",
1044*0Sstevel@tonic-gate parentr->lr_msgid, 0, 0 );
1045*0Sstevel@tonic-gate LDAPDebug( LDAP_DEBUG_TRACE, "result lderrno %d, error <%s>, matched <%s>\n",
1046*0Sstevel@tonic-gate parentr->lr_res_errno, parentr->lr_res_error ?
1047*0Sstevel@tonic-gate parentr->lr_res_error : "", parentr->lr_res_matched ?
1048*0Sstevel@tonic-gate parentr->lr_res_matched : "" );
1049*0Sstevel@tonic-gate }
1050*0Sstevel@tonic-gate
1051*0Sstevel@tonic-gate #if defined( CLDAP )
1052*0Sstevel@tonic-gate #if !defined( macintosh ) && !defined( DOS ) && !defined( _WINDOWS ) && !defined(XP_OS2)
1053*0Sstevel@tonic-gate /* XXXmcs: was revised to support extended I/O callbacks but never compiled! */
1054*0Sstevel@tonic-gate static int
1055*0Sstevel@tonic-gate cldap_select1( LDAP *ld, struct timeval *timeout )
1056*0Sstevel@tonic-gate {
1057*0Sstevel@tonic-gate int rc;
1058*0Sstevel@tonic-gate static int tblsize = 0;
1059*0Sstevel@tonic-gate NSLDAPIIOStatus *iosp = ld->ld_iostatus;
1060*0Sstevel@tonic-gate
1061*0Sstevel@tonic-gate if ( tblsize == 0 ) {
1062*0Sstevel@tonic-gate #ifdef USE_SYSCONF
1063*0Sstevel@tonic-gate tblsize = sysconf( _SC_OPEN_MAX );
1064*0Sstevel@tonic-gate #else /* USE_SYSCONF */
1065*0Sstevel@tonic-gate tblsize = getdtablesize();
1066*0Sstevel@tonic-gate #endif /* USE_SYSCONF */
1067*0Sstevel@tonic-gate }
1068*0Sstevel@tonic-gate
1069*0Sstevel@tonic-gate if ( tblsize >= FD_SETSIZE ) {
1070*0Sstevel@tonic-gate /*
1071*0Sstevel@tonic-gate * clamp value so we don't overrun the fd_set structure
1072*0Sstevel@tonic-gate */
1073*0Sstevel@tonic-gate tblsize = FD_SETSIZE - 1;
1074*0Sstevel@tonic-gate }
1075*0Sstevel@tonic-gate
1076*0Sstevel@tonic-gate if ( NSLDAPI_IOSTATUS_TYPE_OSNATIVE == iosp->ios_type ) {
1077*0Sstevel@tonic-gate fd_set readfds;
1078*0Sstevel@tonic-gate
1079*0Sstevel@tonic-gate FD_ZERO( &readfds );
1080*0Sstevel@tonic-gate FD_SET( ld->ld_sbp->sb_sd, &readfds );
1081*0Sstevel@tonic-gate
1082*0Sstevel@tonic-gate /* XXXmcs: UNIX platforms should use poll() */
1083*0Sstevel@tonic-gate rc = select( tblsize, &readfds, 0, 0, timeout ) );
1084*0Sstevel@tonic-gate
1085*0Sstevel@tonic-gate } else if ( NSLDAPI_IOSTATUS_TYPE_CALLBACK == iosp->ios_type ) {
1086*0Sstevel@tonic-gate LDAP_X_PollFD pollfds[ 1 ];
1087*0Sstevel@tonic-gate
1088*0Sstevel@tonic-gate pollfds[0].lpoll_fd = ld->ld_sbp->sb_sd;
1089*0Sstevel@tonic-gate pollfds[0].lpoll_arg = ld->ld_sbp->sb_arg;
1090*0Sstevel@tonic-gate pollfds[0].lpoll_events = LDAP_X_POLLIN;
1091*0Sstevel@tonic-gate pollfds[0].lpoll_revents = 0;
1092*0Sstevel@tonic-gate rc = ld->ld_extpoll_fn( pollfds, 1, nsldapi_tv2ms( timeout ),
1093*0Sstevel@tonic-gate ld->ld_ext_session_arg );
1094*0Sstevel@tonic-gate } else {
1095*0Sstevel@tonic-gate LDAPDebug( LDAP_DEBUG_ANY,
1096*0Sstevel@tonic-gate "nsldapi_iostatus_poll: unknown I/O type %d\n",
1097*0Sstevel@tonic-gate rc = 0; /* simulate a timeout (what else to do?) */
1098*0Sstevel@tonic-gate }
1099*0Sstevel@tonic-gate
1100*0Sstevel@tonic-gate return( rc );
1101*0Sstevel@tonic-gate }
1102*0Sstevel@tonic-gate #endif /* !macintosh */
1103*0Sstevel@tonic-gate
1104*0Sstevel@tonic-gate
1105*0Sstevel@tonic-gate #ifdef macintosh
1106*0Sstevel@tonic-gate static int
1107*0Sstevel@tonic-gate cldap_select1( LDAP *ld, struct timeval *timeout )
1108*0Sstevel@tonic-gate {
1109*0Sstevel@tonic-gate /* XXXmcs: needs to be revised to support I/O callbacks */
1110*0Sstevel@tonic-gate return( tcpselect( ld->ld_sbp->sb_sd, timeout ));
1111*0Sstevel@tonic-gate }
1112*0Sstevel@tonic-gate #endif /* macintosh */
1113*0Sstevel@tonic-gate
1114*0Sstevel@tonic-gate
1115*0Sstevel@tonic-gate #if (defined( DOS ) && defined( WINSOCK )) || defined( _WINDOWS ) || defined(XP_OS2)
1116*0Sstevel@tonic-gate /* XXXmcs: needs to be revised to support extended I/O callbacks */
1117*0Sstevel@tonic-gate static int
1118*0Sstevel@tonic-gate cldap_select1( LDAP *ld, struct timeval *timeout )
1119*0Sstevel@tonic-gate {
1120*0Sstevel@tonic-gate fd_set readfds;
1121*0Sstevel@tonic-gate int rc;
1122*0Sstevel@tonic-gate
1123*0Sstevel@tonic-gate FD_ZERO( &readfds );
1124*0Sstevel@tonic-gate FD_SET( ld->ld_sbp->sb_sd, &readfds );
1125*0Sstevel@tonic-gate
1126*0Sstevel@tonic-gate if ( NSLDAPI_IO_TYPE_STANDARD == ld->ldiou_type &&
1127*0Sstevel@tonic-gate NULL != ld->ld_select_fn ) {
1128*0Sstevel@tonic-gate rc = ld->ld_select_fn( 1, &readfds, 0, 0, timeout );
1129*0Sstevel@tonic-gate } else if ( NSLDAPI_IO_TYPE_EXTENDED == ld->ldiou_type &&
1130*0Sstevel@tonic-gate NULL != ld->ld_extselect_fn ) {
1131*0Sstevel@tonic-gate rc = ld->ld_extselect_fn( ld->ld_ext_session_arg, 1, &readfds, 0,
1132*0Sstevel@tonic-gate 0, timeout ) );
1133*0Sstevel@tonic-gate } else {
1134*0Sstevel@tonic-gate /* XXXmcs: UNIX platforms should use poll() */
1135*0Sstevel@tonic-gate rc = select( 1, &readfds, 0, 0, timeout ) );
1136*0Sstevel@tonic-gate }
1137*0Sstevel@tonic-gate
1138*0Sstevel@tonic-gate return( rc == SOCKET_ERROR ? -1 : rc );
1139*0Sstevel@tonic-gate }
1140*0Sstevel@tonic-gate #endif /* WINSOCK || _WINDOWS */
1141*0Sstevel@tonic-gate #endif /* CLDAP */
1142*0Sstevel@tonic-gate
1143*0Sstevel@tonic-gate int
1144*0Sstevel@tonic-gate LDAP_CALL
1145*0Sstevel@tonic-gate ldap_msgfree( LDAPMessage *lm )
1146*0Sstevel@tonic-gate {
1147*0Sstevel@tonic-gate LDAPMessage *next;
1148*0Sstevel@tonic-gate int type = 0;
1149*0Sstevel@tonic-gate
1150*0Sstevel@tonic-gate LDAPDebug( LDAP_DEBUG_TRACE, "ldap_msgfree\n", 0, 0, 0 );
1151*0Sstevel@tonic-gate
1152*0Sstevel@tonic-gate for ( ; lm != NULL; lm = next ) {
1153*0Sstevel@tonic-gate next = lm->lm_chain;
1154*0Sstevel@tonic-gate type = lm->lm_msgtype;
1155*0Sstevel@tonic-gate ber_free( lm->lm_ber, 1 );
1156*0Sstevel@tonic-gate NSLDAPI_FREE( (char *) lm );
1157*0Sstevel@tonic-gate }
1158*0Sstevel@tonic-gate
1159*0Sstevel@tonic-gate return( type );
1160*0Sstevel@tonic-gate }
1161*0Sstevel@tonic-gate
1162*0Sstevel@tonic-gate /*
1163*0Sstevel@tonic-gate * ldap_msgdelete - delete a message. It returns:
1164*0Sstevel@tonic-gate * 0 if the entire message was deleted
1165*0Sstevel@tonic-gate * -1 if the message was not found, or only part of it was found
1166*0Sstevel@tonic-gate */
1167*0Sstevel@tonic-gate int
1168*0Sstevel@tonic-gate ldap_msgdelete( LDAP *ld, int msgid )
1169*0Sstevel@tonic-gate {
1170*0Sstevel@tonic-gate LDAPMessage *lm, *prev;
1171*0Sstevel@tonic-gate int msgtype;
1172*0Sstevel@tonic-gate
1173*0Sstevel@tonic-gate LDAPDebug( LDAP_DEBUG_TRACE, "ldap_msgdelete\n", 0, 0, 0 );
1174*0Sstevel@tonic-gate
1175*0Sstevel@tonic-gate if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
1176*0Sstevel@tonic-gate return( -1 ); /* punt */
1177*0Sstevel@tonic-gate }
1178*0Sstevel@tonic-gate
1179*0Sstevel@tonic-gate prev = NULL;
1180*0Sstevel@tonic-gate LDAP_MUTEX_LOCK( ld, LDAP_RESP_LOCK );
1181*0Sstevel@tonic-gate for ( lm = ld->ld_responses; lm != NULL; lm = lm->lm_next ) {
1182*0Sstevel@tonic-gate if ( lm->lm_msgid == msgid )
1183*0Sstevel@tonic-gate break;
1184*0Sstevel@tonic-gate prev = lm;
1185*0Sstevel@tonic-gate }
1186*0Sstevel@tonic-gate
1187*0Sstevel@tonic-gate if ( lm == NULL )
1188*0Sstevel@tonic-gate {
1189*0Sstevel@tonic-gate LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
1190*0Sstevel@tonic-gate return( -1 );
1191*0Sstevel@tonic-gate }
1192*0Sstevel@tonic-gate
1193*0Sstevel@tonic-gate if ( prev == NULL )
1194*0Sstevel@tonic-gate ld->ld_responses = lm->lm_next;
1195*0Sstevel@tonic-gate else
1196*0Sstevel@tonic-gate prev->lm_next = lm->lm_next;
1197*0Sstevel@tonic-gate LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
1198*0Sstevel@tonic-gate
1199*0Sstevel@tonic-gate msgtype = ldap_msgfree( lm );
1200*0Sstevel@tonic-gate if ( msgtype == LDAP_RES_SEARCH_ENTRY
1201*0Sstevel@tonic-gate || msgtype == LDAP_RES_SEARCH_REFERENCE ) {
1202*0Sstevel@tonic-gate return( -1 );
1203*0Sstevel@tonic-gate }
1204*0Sstevel@tonic-gate
1205*0Sstevel@tonic-gate return( 0 );
1206*0Sstevel@tonic-gate }
1207*0Sstevel@tonic-gate
1208*0Sstevel@tonic-gate
1209*0Sstevel@tonic-gate /*
1210*0Sstevel@tonic-gate * return 1 if message msgid is waiting to be abandoned, 0 otherwise
1211*0Sstevel@tonic-gate */
1212*0Sstevel@tonic-gate static int
1213*0Sstevel@tonic-gate ldap_abandoned( LDAP *ld, int msgid )
1214*0Sstevel@tonic-gate {
1215*0Sstevel@tonic-gate int i;
1216*0Sstevel@tonic-gate
1217*0Sstevel@tonic-gate LDAP_MUTEX_LOCK( ld, LDAP_ABANDON_LOCK );
1218*0Sstevel@tonic-gate if ( ld->ld_abandoned == NULL )
1219*0Sstevel@tonic-gate {
1220*0Sstevel@tonic-gate LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
1221*0Sstevel@tonic-gate return( 0 );
1222*0Sstevel@tonic-gate }
1223*0Sstevel@tonic-gate
1224*0Sstevel@tonic-gate for ( i = 0; ld->ld_abandoned[i] != -1; i++ )
1225*0Sstevel@tonic-gate if ( ld->ld_abandoned[i] == msgid )
1226*0Sstevel@tonic-gate {
1227*0Sstevel@tonic-gate LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
1228*0Sstevel@tonic-gate return( 1 );
1229*0Sstevel@tonic-gate }
1230*0Sstevel@tonic-gate
1231*0Sstevel@tonic-gate LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
1232*0Sstevel@tonic-gate return( 0 );
1233*0Sstevel@tonic-gate }
1234*0Sstevel@tonic-gate
1235*0Sstevel@tonic-gate
1236*0Sstevel@tonic-gate static int
1237*0Sstevel@tonic-gate ldap_mark_abandoned( LDAP *ld, int msgid )
1238*0Sstevel@tonic-gate {
1239*0Sstevel@tonic-gate int i;
1240*0Sstevel@tonic-gate
1241*0Sstevel@tonic-gate LDAP_MUTEX_LOCK( ld, LDAP_ABANDON_LOCK );
1242*0Sstevel@tonic-gate if ( ld->ld_abandoned == NULL )
1243*0Sstevel@tonic-gate {
1244*0Sstevel@tonic-gate LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
1245*0Sstevel@tonic-gate return( -1 );
1246*0Sstevel@tonic-gate }
1247*0Sstevel@tonic-gate
1248*0Sstevel@tonic-gate for ( i = 0; ld->ld_abandoned[i] != -1; i++ )
1249*0Sstevel@tonic-gate if ( ld->ld_abandoned[i] == msgid )
1250*0Sstevel@tonic-gate break;
1251*0Sstevel@tonic-gate
1252*0Sstevel@tonic-gate if ( ld->ld_abandoned[i] == -1 )
1253*0Sstevel@tonic-gate {
1254*0Sstevel@tonic-gate LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
1255*0Sstevel@tonic-gate return( -1 );
1256*0Sstevel@tonic-gate }
1257*0Sstevel@tonic-gate
1258*0Sstevel@tonic-gate for ( ; ld->ld_abandoned[i] != -1; i++ ) {
1259*0Sstevel@tonic-gate ld->ld_abandoned[i] = ld->ld_abandoned[i + 1];
1260*0Sstevel@tonic-gate }
1261*0Sstevel@tonic-gate
1262*0Sstevel@tonic-gate LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
1263*0Sstevel@tonic-gate return( 0 );
1264*0Sstevel@tonic-gate }
1265*0Sstevel@tonic-gate
1266*0Sstevel@tonic-gate
1267*0Sstevel@tonic-gate #ifdef CLDAP
1268*0Sstevel@tonic-gate int
1269*0Sstevel@tonic-gate cldap_getmsg( LDAP *ld, struct timeval *timeout, BerElement **ber )
1270*0Sstevel@tonic-gate {
1271*0Sstevel@tonic-gate int rc;
1272*0Sstevel@tonic-gate ber_tag_t tag;
1273*0Sstevel@tonic-gate ber_len_t len;
1274*0Sstevel@tonic-gate
1275*0Sstevel@tonic-gate if ( ld->ld_sbp->sb_ber.ber_ptr >= ld->ld_sbp->sb_ber.ber_end ) {
1276*0Sstevel@tonic-gate rc = cldap_select1( ld, timeout );
1277*0Sstevel@tonic-gate if ( rc == -1 || rc == 0 ) {
1278*0Sstevel@tonic-gate LDAP_SET_LDERRNO( ld, (rc == -1 ? LDAP_SERVER_DOWN :
1279*0Sstevel@tonic-gate LDAP_TIMEOUT), NULL, NULL );
1280*0Sstevel@tonic-gate return( rc );
1281*0Sstevel@tonic-gate }
1282*0Sstevel@tonic-gate }
1283*0Sstevel@tonic-gate
1284*0Sstevel@tonic-gate /* get the next message */
1285*0Sstevel@tonic-gate if ( (tag = ber_get_next( ld->ld_sbp, &len, ber ))
1286*0Sstevel@tonic-gate != LDAP_TAG_MESSAGE ) {
1287*0Sstevel@tonic-gate LDAP_SET_LDERRNO( ld, (tag == LBER_DEFAULT ? LDAP_SERVER_DOWN :
1288*0Sstevel@tonic-gate LDAP_LOCAL_ERROR), NULL, NULL );
1289*0Sstevel@tonic-gate return( -1 );
1290*0Sstevel@tonic-gate }
1291*0Sstevel@tonic-gate
1292*0Sstevel@tonic-gate return( tag );
1293*0Sstevel@tonic-gate }
1294*0Sstevel@tonic-gate #endif /* CLDAP */
1295*0Sstevel@tonic-gate
1296*0Sstevel@tonic-gate int
1297*0Sstevel@tonic-gate nsldapi_post_result( LDAP *ld, int msgid, LDAPMessage *result )
1298*0Sstevel@tonic-gate {
1299*0Sstevel@tonic-gate LDAPPend *lp;
1300*0Sstevel@tonic-gate
1301*0Sstevel@tonic-gate LDAPDebug( LDAP_DEBUG_TRACE,
1302*0Sstevel@tonic-gate "nsldapi_post_result(ld=0x%x, msgid=%d, result=0x%x)\n",
1303*0Sstevel@tonic-gate ld, msgid, result );
1304*0Sstevel@tonic-gate LDAP_MUTEX_LOCK( ld, LDAP_PEND_LOCK );
1305*0Sstevel@tonic-gate if( msgid == LDAP_RES_ANY ) {
1306*0Sstevel@tonic-gate /*
1307*0Sstevel@tonic-gate * Look for any pending request for which someone is waiting.
1308*0Sstevel@tonic-gate */
1309*0Sstevel@tonic-gate for( lp = ld->ld_pend; lp != NULL; lp = lp->lp_next )
1310*0Sstevel@tonic-gate {
1311*0Sstevel@tonic-gate if ( lp->lp_sema != NULL ) {
1312*0Sstevel@tonic-gate break;
1313*0Sstevel@tonic-gate }
1314*0Sstevel@tonic-gate }
1315*0Sstevel@tonic-gate /*
1316*0Sstevel@tonic-gate * If we did't find a pending request, lp is NULL at this
1317*0Sstevel@tonic-gate * point, and we will leave this function without doing
1318*0Sstevel@tonic-gate * anything more -- which is exactly what we want to do.
1319*0Sstevel@tonic-gate */
1320*0Sstevel@tonic-gate }
1321*0Sstevel@tonic-gate else
1322*0Sstevel@tonic-gate {
1323*0Sstevel@tonic-gate /*
1324*0Sstevel@tonic-gate * Look for a pending request specific to this message id
1325*0Sstevel@tonic-gate */
1326*0Sstevel@tonic-gate for( lp = ld->ld_pend; lp != NULL; lp = lp->lp_next )
1327*0Sstevel@tonic-gate {
1328*0Sstevel@tonic-gate if( lp->lp_msgid == msgid )
1329*0Sstevel@tonic-gate break;
1330*0Sstevel@tonic-gate }
1331*0Sstevel@tonic-gate
1332*0Sstevel@tonic-gate if( lp == NULL )
1333*0Sstevel@tonic-gate {
1334*0Sstevel@tonic-gate /*
1335*0Sstevel@tonic-gate * No pending requests for this response... append to
1336*0Sstevel@tonic-gate * our pending result list.
1337*0Sstevel@tonic-gate */
1338*0Sstevel@tonic-gate LDAPPend *newlp;
1339*0Sstevel@tonic-gate newlp = (LDAPPend *)NSLDAPI_CALLOC( 1,
1340*0Sstevel@tonic-gate sizeof( LDAPPend ));
1341*0Sstevel@tonic-gate if( newlp == NULL )
1342*0Sstevel@tonic-gate {
1343*0Sstevel@tonic-gate LDAP_MUTEX_UNLOCK( ld, LDAP_PEND_LOCK );
1344*0Sstevel@tonic-gate LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL,
1345*0Sstevel@tonic-gate NULL );
1346*0Sstevel@tonic-gate return (-1);
1347*0Sstevel@tonic-gate }
1348*0Sstevel@tonic-gate newlp->lp_msgid = msgid;
1349*0Sstevel@tonic-gate newlp->lp_result = result;
1350*0Sstevel@tonic-gate link_pend( ld, newlp );
1351*0Sstevel@tonic-gate }
1352*0Sstevel@tonic-gate }
1353*0Sstevel@tonic-gate
1354*0Sstevel@tonic-gate
1355*0Sstevel@tonic-gate if( lp != NULL )
1356*0Sstevel@tonic-gate {
1357*0Sstevel@tonic-gate /*
1358*0Sstevel@tonic-gate * Wake up a thread that is waiting for this result.
1359*0Sstevel@tonic-gate */
1360*0Sstevel@tonic-gate lp->lp_msgid = msgid;
1361*0Sstevel@tonic-gate lp->lp_result = result;
1362*0Sstevel@tonic-gate LDAP_SEMA_POST( ld, lp );
1363*0Sstevel@tonic-gate }
1364*0Sstevel@tonic-gate
1365*0Sstevel@tonic-gate LDAP_MUTEX_UNLOCK( ld, LDAP_PEND_LOCK );
1366*0Sstevel@tonic-gate return (0);
1367*0Sstevel@tonic-gate }
1368*0Sstevel@tonic-gate
1369*0Sstevel@tonic-gate static void
1370*0Sstevel@tonic-gate link_pend( LDAP *ld, LDAPPend *lp )
1371*0Sstevel@tonic-gate {
1372*0Sstevel@tonic-gate if (( lp->lp_next = ld->ld_pend ) != NULL )
1373*0Sstevel@tonic-gate {
1374*0Sstevel@tonic-gate lp->lp_next->lp_prev = lp;
1375*0Sstevel@tonic-gate }
1376*0Sstevel@tonic-gate ld->ld_pend = lp;
1377*0Sstevel@tonic-gate lp->lp_prev = NULL;
1378*0Sstevel@tonic-gate }
1379*0Sstevel@tonic-gate
1380*0Sstevel@tonic-gate #if 0 /* these functions are no longer used */
1381*0Sstevel@tonic-gate static void
1382*0Sstevel@tonic-gate unlink_pend( LDAP *ld, LDAPPend *lp )
1383*0Sstevel@tonic-gate {
1384*0Sstevel@tonic-gate if ( lp->lp_prev == NULL ) {
1385*0Sstevel@tonic-gate ld->ld_pend = lp->lp_next;
1386*0Sstevel@tonic-gate } else {
1387*0Sstevel@tonic-gate lp->lp_prev->lp_next = lp->lp_next;
1388*0Sstevel@tonic-gate }
1389*0Sstevel@tonic-gate
1390*0Sstevel@tonic-gate if ( lp->lp_next != NULL ) {
1391*0Sstevel@tonic-gate lp->lp_next->lp_prev = lp->lp_prev;
1392*0Sstevel@tonic-gate }
1393*0Sstevel@tonic-gate }
1394*0Sstevel@tonic-gate
1395*0Sstevel@tonic-gate static int
1396*0Sstevel@tonic-gate unlink_msg( LDAP *ld, int msgid, int all )
1397*0Sstevel@tonic-gate {
1398*0Sstevel@tonic-gate int rc;
1399*0Sstevel@tonic-gate LDAPMessage *lm, *lastlm, *nextlm;
1400*0Sstevel@tonic-gate
1401*0Sstevel@tonic-gate lastlm = NULL;
1402*0Sstevel@tonic-gate LDAP_MUTEX_LOCK( ld, LDAP_RESP_LOCK );
1403*0Sstevel@tonic-gate for ( lm = ld->ld_responses; lm != NULL; lm = nextlm )
1404*0Sstevel@tonic-gate {
1405*0Sstevel@tonic-gate nextlm = lm->lm_next;
1406*0Sstevel@tonic-gate
1407*0Sstevel@tonic-gate if ( lm->lm_msgid == msgid )
1408*0Sstevel@tonic-gate {
1409*0Sstevel@tonic-gate LDAPMessage *tmp;
1410*0Sstevel@tonic-gate
1411*0Sstevel@tonic-gate if ( all == 0
1412*0Sstevel@tonic-gate || (lm->lm_msgtype != LDAP_RES_SEARCH_RESULT
1413*0Sstevel@tonic-gate && lm->lm_msgtype != LDAP_RES_SEARCH_REFERENCE
1414*0Sstevel@tonic-gate && lm->lm_msgtype != LDAP_RES_SEARCH_ENTRY) )
1415*0Sstevel@tonic-gate break;
1416*0Sstevel@tonic-gate
1417*0Sstevel@tonic-gate for ( tmp = lm; tmp != NULL; tmp = tmp->lm_chain ) {
1418*0Sstevel@tonic-gate if ( tmp->lm_msgtype == LDAP_RES_SEARCH_RESULT )
1419*0Sstevel@tonic-gate break;
1420*0Sstevel@tonic-gate }
1421*0Sstevel@tonic-gate if( tmp != NULL )
1422*0Sstevel@tonic-gate break;
1423*0Sstevel@tonic-gate }
1424*0Sstevel@tonic-gate lastlm = lm;
1425*0Sstevel@tonic-gate }
1426*0Sstevel@tonic-gate
1427*0Sstevel@tonic-gate if( lm != NULL )
1428*0Sstevel@tonic-gate {
1429*0Sstevel@tonic-gate
1430*0Sstevel@tonic-gate if ( all == 0 )
1431*0Sstevel@tonic-gate {
1432*0Sstevel@tonic-gate if ( lm->lm_chain == NULL )
1433*0Sstevel@tonic-gate {
1434*0Sstevel@tonic-gate if ( lastlm == NULL )
1435*0Sstevel@tonic-gate ld->ld_responses = lm->lm_next;
1436*0Sstevel@tonic-gate else
1437*0Sstevel@tonic-gate lastlm->lm_next = lm->lm_next;
1438*0Sstevel@tonic-gate }
1439*0Sstevel@tonic-gate else
1440*0Sstevel@tonic-gate {
1441*0Sstevel@tonic-gate if ( lastlm == NULL )
1442*0Sstevel@tonic-gate {
1443*0Sstevel@tonic-gate ld->ld_responses = lm->lm_chain;
1444*0Sstevel@tonic-gate ld->ld_responses->lm_next = lm->lm_next;
1445*0Sstevel@tonic-gate }
1446*0Sstevel@tonic-gate else
1447*0Sstevel@tonic-gate {
1448*0Sstevel@tonic-gate lastlm->lm_next = lm->lm_chain;
1449*0Sstevel@tonic-gate lastlm->lm_next->lm_next = lm->lm_next;
1450*0Sstevel@tonic-gate }
1451*0Sstevel@tonic-gate }
1452*0Sstevel@tonic-gate }
1453*0Sstevel@tonic-gate else
1454*0Sstevel@tonic-gate {
1455*0Sstevel@tonic-gate if ( lastlm == NULL )
1456*0Sstevel@tonic-gate ld->ld_responses = lm->lm_next;
1457*0Sstevel@tonic-gate else
1458*0Sstevel@tonic-gate lastlm->lm_next = lm->lm_next;
1459*0Sstevel@tonic-gate }
1460*0Sstevel@tonic-gate
1461*0Sstevel@tonic-gate if ( all == 0 )
1462*0Sstevel@tonic-gate lm->lm_chain = NULL;
1463*0Sstevel@tonic-gate lm->lm_next = NULL;
1464*0Sstevel@tonic-gate rc = lm->lm_msgtype;
1465*0Sstevel@tonic-gate }
1466*0Sstevel@tonic-gate else
1467*0Sstevel@tonic-gate {
1468*0Sstevel@tonic-gate rc = -2;
1469*0Sstevel@tonic-gate }
1470*0Sstevel@tonic-gate LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
1471*0Sstevel@tonic-gate return ( rc );
1472*0Sstevel@tonic-gate }
1473*0Sstevel@tonic-gate #endif /* 0 */
1474