8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / libldap5 / sources / ldap / common / result.c
blobecf807653a28ca5434cafbfdbbce92c73d7c72f0
1 /*
2 * Copyright 2001-2003 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
6 #pragma ident "%Z%%M% %I% %E% SMI"
8 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
10 * The contents of this file are subject to the Netscape Public License
11 * Version 1.0 (the "NPL"); you may not use this file except in
12 * compliance with the NPL. You may obtain a copy of the NPL at
13 * http://www.mozilla.org/NPL/
15 * Software distributed under the NPL is distributed on an "AS IS" basis,
16 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
17 * for the specific language governing rights and limitations under the
18 * NPL.
20 * The Initial Developer of this code under the NPL is Netscape
21 * Communications Corporation. Portions created by Netscape are
22 * Copyright (C) 1998 Netscape Communications Corporation. All Rights
23 * Reserved.
26 * Copyright (c) 1990 Regents of the University of Michigan.
27 * All rights reserved.
30 * result.c - wait for an ldap result
33 #if 0
34 #ifndef lint
35 static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
36 #endif
37 #endif
39 #include "ldap-int.h"
41 #ifdef _SOLARIS_SDK
42 /* high resolution timer usage */
43 #include <sys/time.h>
44 #endif
46 static int check_response_queue( LDAP *ld, int msgid, int all,
47 int do_abandon_check, LDAPMessage **result );
48 static int ldap_abandoned( LDAP *ld, int msgid );
49 static int ldap_mark_abandoned( LDAP *ld, int msgid );
50 static int wait4msg( LDAP *ld, int msgid, int all, int unlock_permitted,
51 struct timeval *timeout, LDAPMessage **result );
52 static int read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb, LDAPConn *lc,
53 LDAPMessage **result );
54 static void check_for_refs( LDAP *ld, LDAPRequest *lr, BerElement *ber,
55 int ldapversion, int *totalcountp, int *chasingcountp );
56 static int build_result_ber( LDAP *ld, BerElement **berp, LDAPRequest *lr );
57 static void merge_error_info( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr );
58 #if defined( CLDAP )
59 static int cldap_select1( LDAP *ld, struct timeval *timeout );
60 #endif
61 static void link_pend( LDAP *ld, LDAPPend *lp );
62 #if 0 /* these functions are no longer used */
63 static void unlink_pend( LDAP *ld, LDAPPend *lp );
64 static int unlink_msg( LDAP *ld, int msgid, int all );
65 #endif /* 0 */
68 * ldap_result - wait for an ldap result response to a message from the
69 * ldap server. If msgid is -1, any message will be accepted, otherwise
70 * ldap_result will wait for a response with msgid. If all is 0 the
71 * first message with id msgid will be accepted, otherwise, ldap_result
72 * will wait for all responses with id msgid and then return a pointer to
73 * the entire list of messages. This is only useful for search responses,
74 * which can be of two message types (zero or more entries, followed by an
75 * ldap result). The type of the first message received is returned.
76 * When waiting, any messages that have been abandoned are discarded.
78 * Example:
79 * ldap_result( s, msgid, all, timeout, result )
81 int
82 LDAP_CALL
83 ldap_result(
84 LDAP *ld,
85 int msgid,
86 int all,
87 struct timeval *timeout,
88 LDAPMessage **result
91 int rc;
93 LDAPDebug( LDAP_DEBUG_TRACE, "ldap_result\n", 0, 0, 0 );
95 if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
96 return( -1 ); /* punt */
99 LDAP_MUTEX_LOCK( ld, LDAP_RESULT_LOCK );
101 rc = nsldapi_result_nolock(ld, msgid, all, 1, timeout, result);
103 LDAP_MUTEX_UNLOCK( ld, LDAP_RESULT_LOCK );
105 return( rc );
110 nsldapi_result_nolock( LDAP *ld, int msgid, int all, int unlock_permitted,
111 struct timeval *timeout, LDAPMessage **result )
113 int rc;
115 LDAPDebug( LDAP_DEBUG_TRACE,
116 "nsldapi_result_nolock (msgid=%d, all=%d)\n", msgid, all, 0 );
119 * First, look through the list of responses we have received on
120 * this association and see if the response we're interested in
121 * is there. If it is, return it. If not, call wait4msg() to
122 * wait until it arrives or timeout occurs.
125 if ( result == NULL ) {
126 LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
127 return( -1 );
130 if ( check_response_queue( ld, msgid, all, 1, result ) != 0 ) {
131 LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, NULL );
132 rc = (*result)->lm_msgtype;
133 } else {
134 rc = wait4msg( ld, msgid, all, unlock_permitted, timeout,
135 result );
139 * XXXmcs should use cache function pointers to hook in memcache
141 if ( ld->ld_memcache != NULL && NSLDAPI_SEARCH_RELATED_RESULT( rc ) &&
142 !((*result)->lm_fromcache )) {
143 ldap_memcache_append( ld, (*result)->lm_msgid,
144 (all || NSLDAPI_IS_SEARCH_RESULT( rc )), *result );
147 return( rc );
152 * Look through the list of queued responses for a message that matches the
153 * criteria in the msgid and all parameters. msgid == LDAP_RES_ANY matches
154 * all ids.
156 * If an appropriate message is found, a non-zero value is returned and the
157 * message is dequeued and assigned to *result.
159 * If not, *result is set to NULL and this function returns 0.
161 static int
162 check_response_queue( LDAP *ld, int msgid, int all, int do_abandon_check,
163 LDAPMessage **result )
165 LDAPMessage *lm, *lastlm, *nextlm;
166 LDAPRequest *lr;
168 LDAPDebug( LDAP_DEBUG_TRACE,
169 "=> check_response_queue (msgid=%d, all=%d)\n", msgid, all, 0 );
171 *result = NULL;
172 lastlm = NULL;
173 LDAP_MUTEX_LOCK( ld, LDAP_RESP_LOCK );
174 for ( lm = ld->ld_responses; lm != NULL; lm = nextlm ) {
175 nextlm = lm->lm_next;
177 if ( do_abandon_check && ldap_abandoned( ld, lm->lm_msgid ) ) {
178 ldap_mark_abandoned( ld, lm->lm_msgid );
180 if ( lastlm == NULL ) {
181 ld->ld_responses = lm->lm_next;
182 } else {
183 lastlm->lm_next = nextlm;
186 ldap_msgfree( lm );
188 continue;
191 if ( msgid == LDAP_RES_ANY || lm->lm_msgid == msgid ) {
192 LDAPMessage *tmp;
194 if ( all == 0
195 || (lm->lm_msgtype != LDAP_RES_SEARCH_RESULT
196 && lm->lm_msgtype != LDAP_RES_SEARCH_REFERENCE
197 && lm->lm_msgtype != LDAP_RES_SEARCH_ENTRY) )
198 break;
200 for ( tmp = lm; tmp != NULL; tmp = tmp->lm_chain ) {
201 if ( tmp->lm_msgtype == LDAP_RES_SEARCH_RESULT )
202 break;
205 if ( tmp == NULL ) {
206 LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
207 LDAPDebug( LDAP_DEBUG_TRACE,
208 "<= check_response_queue NOT FOUND\n",
209 0, 0, 0 );
210 return( 0 ); /* no message to return */
213 break;
215 lastlm = lm;
219 * if we did not find a message OR if the one we found is a result for
220 * a request that is still pending, return failure.
222 if ( lm == NULL
223 || (( lr = nsldapi_find_request_by_msgid( ld, lm->lm_msgid ))
224 != NULL && lr->lr_outrefcnt > 0 )) {
225 LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
226 LDAPDebug( LDAP_DEBUG_TRACE,
227 "<= check_response_queue NOT FOUND\n",
228 0, 0, 0 );
229 return( 0 ); /* no message to return */
232 if ( all == 0 ) {
233 if ( lm->lm_chain == NULL ) {
234 if ( lastlm == NULL ) {
235 ld->ld_responses = lm->lm_next;
236 } else {
237 lastlm->lm_next = lm->lm_next;
239 } else {
240 if ( lastlm == NULL ) {
241 ld->ld_responses = lm->lm_chain;
242 ld->ld_responses->lm_next = lm->lm_next;
243 } else {
244 lastlm->lm_next = lm->lm_chain;
245 lastlm->lm_next->lm_next = lm->lm_next;
248 } else {
249 if ( lastlm == NULL ) {
250 ld->ld_responses = lm->lm_next;
251 } else {
252 lastlm->lm_next = lm->lm_next;
256 if ( all == 0 ) {
257 lm->lm_chain = NULL;
259 lm->lm_next = NULL;
260 LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
262 *result = lm;
263 LDAPDebug( LDAP_DEBUG_TRACE,
264 "<= check_response_queue returning msgid %d type %d\n",
265 lm->lm_msgid, lm->lm_msgtype, 0 );
266 return( 1 ); /* a message was found and returned in *result */
270 static int
271 wait4msg( LDAP *ld, int msgid, int all, int unlock_permitted,
272 struct timeval *timeout, LDAPMessage **result )
274 int rc;
275 struct timeval tv, *tvp;
276 #ifdef _SOLARIS_SDK
277 hrtime_t start_time = 0, tmp_time, tv_time;
278 #else
279 long start_time = 0, tmp_time;
280 #endif
281 LDAPConn *lc, *nextlc;
282 LDAPRequest *lr;
284 #ifdef LDAP_DEBUG
285 if ( timeout == NULL ) {
286 LDAPDebug( LDAP_DEBUG_TRACE, "wait4msg (infinite timeout)\n",
287 0, 0, 0 );
288 } else {
289 LDAPDebug( LDAP_DEBUG_TRACE, "wait4msg (timeout %ld sec, %ld usec)\n",
290 timeout->tv_sec, timeout->tv_usec, 0 );
292 #endif /* LDAP_DEBUG */
294 /* check the cache */
295 if ( ld->ld_cache_on && ld->ld_cache_result != NULL ) {
296 /* if ( unlock_permitted ) LDAP_MUTEX_UNLOCK( ld ); */
297 LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK );
298 rc = (ld->ld_cache_result)( ld, msgid, all, timeout, result );
299 LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
300 /* if ( unlock_permitted ) LDAP_MUTEX_LOCK( ld ); */
301 if ( rc != 0 ) {
302 return( rc );
304 if ( ld->ld_cache_strategy == LDAP_CACHE_LOCALDB ) {
305 LDAP_SET_LDERRNO( ld, LDAP_TIMEOUT, NULL, NULL );
306 return( 0 ); /* timeout */
311 * if we are looking for a specific msgid, check to see if it is
312 * associated with a dead connection and return an error if so.
314 if ( msgid != LDAP_RES_ANY && msgid != LDAP_RES_UNSOLICITED ) {
315 LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
316 if (( lr = nsldapi_find_request_by_msgid( ld, msgid ))
317 == NULL ) {
318 LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
319 LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL,
320 nsldapi_strdup( dgettext(TEXT_DOMAIN,
321 "unknown message id") ));
322 return( -1 ); /* could not find request for msgid */
324 if ( lr->lr_conn != NULL &&
325 lr->lr_conn->lconn_status == LDAP_CONNST_DEAD ) {
326 nsldapi_free_request( ld, lr, 1 );
327 LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
328 LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN, NULL, NULL );
329 return( -1 ); /* connection dead */
331 LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
334 if ( timeout == NULL ) {
335 tvp = NULL;
336 } else {
337 tv = *timeout;
338 tvp = &tv;
339 #ifdef _SOLARIS_SDK
340 start_time = gethrtime();
341 tv_time = ((hrtime_t)tv.tv_sec * NANOSEC +
342 (hrtime_t)tv.tv_usec * (NANOSEC / MICROSEC));
343 #else
344 start_time = (long)time( NULL );
345 #endif
348 rc = -2;
349 while ( rc == -2 ) {
350 #ifdef LDAP_DEBUG
351 if ( ldap_debug & LDAP_DEBUG_TRACE ) {
352 nsldapi_dump_connection( ld, ld->ld_conns, 1 );
353 nsldapi_dump_requests_and_responses( ld );
355 #endif /* LDAP_DEBUG */
356 LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK );
357 LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
358 for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {
359 if ( lc->lconn_sb->sb_ber.ber_ptr <
360 lc->lconn_sb->sb_ber.ber_end ) {
361 rc = read1msg( ld, msgid, all, lc->lconn_sb,
362 lc, result );
363 break;
366 LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
367 LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
369 if ( lc == NULL ) {
370 rc = nsldapi_iostatus_poll( ld, tvp );
372 #if defined( LDAP_DEBUG ) && !defined( macintosh ) && !defined( DOS )
373 if ( rc == -1 ) {
374 LDAPDebug( LDAP_DEBUG_TRACE,
375 "nsldapi_iostatus_poll returned -1: errno %d\n",
376 LDAP_GET_ERRNO( ld ), 0, 0 );
378 #endif
380 #if !defined( macintosh ) && !defined( DOS )
381 if ( rc == 0 || ( rc == -1 && (( ld->ld_options &
382 LDAP_BITOPT_RESTART ) == 0 ||
383 LDAP_GET_ERRNO( ld ) != EINTR ))) {
384 #else
385 if ( rc == -1 || rc == 0 ) {
386 #endif
387 LDAP_SET_LDERRNO( ld, (rc == -1 ?
388 LDAP_SERVER_DOWN : LDAP_TIMEOUT), NULL,
389 NULL );
390 if ( rc == -1 ) {
391 LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
392 nsldapi_connection_lost_nolock( ld,
393 NULL );
394 LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
396 return( rc );
399 if ( rc == -1 ) {
400 rc = -2; /* select interrupted: loop */
401 } else {
402 rc = -2;
403 LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK );
404 LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
405 for ( lc = ld->ld_conns; rc == -2 && lc != NULL;
406 lc = nextlc ) {
407 nextlc = lc->lconn_next;
408 if ( lc->lconn_status ==
409 LDAP_CONNST_CONNECTED &&
410 nsldapi_iostatus_is_read_ready( ld,
411 lc->lconn_sb )) {
412 rc = read1msg( ld, msgid, all,
413 lc->lconn_sb, lc, result );
415 else if (ld->ld_options & LDAP_BITOPT_ASYNC) {
416 if ( lr
417 && lc->lconn_status == LDAP_CONNST_CONNECTING
418 && nsldapi_iostatus_is_write_ready( ld,
419 lc->lconn_sb ) ) {
420 rc = nsldapi_ber_flush( ld, lc->lconn_sb, lr->lr_ber, 0, 1 );
421 if ( rc == 0 ) {
422 rc = LDAP_RES_BIND;
423 lc->lconn_status = LDAP_CONNST_CONNECTED;
425 lr->lr_ber->ber_end = lr->lr_ber->ber_ptr;
426 lr->lr_ber->ber_ptr = lr->lr_ber->ber_buf;
427 nsldapi_iostatus_interest_read( ld, lc->lconn_sb );
429 else if ( rc == -1 ) {
430 LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN, NULL, NULL );
431 nsldapi_free_request( ld, lr, 0 );
432 nsldapi_free_connection( ld, lc, NULL, NULL,
433 0, 0 );
439 LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
440 LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
445 * It is possible that recursion occurred while chasing
446 * referrals and as a result the message we are looking
447 * for may have been placed on the response queue. Look
448 * for it there before continuing so we don't end up
449 * waiting on the network for a message that we already
450 * received!
452 if ( rc == -2 &&
453 check_response_queue( ld, msgid, all, 0, result ) != 0 ) {
454 LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, NULL );
455 rc = (*result)->lm_msgtype;
459 * honor the timeout if specified
461 if ( rc == -2 && tvp != NULL ) {
462 #ifdef _SOLARIS_SDK
463 tmp_time = gethrtime();
464 if ((tv_time -= (tmp_time - start_time)) <= 0) {
465 #else
466 tmp_time = (long)time( NULL );
467 if (( tv.tv_sec -= ( tmp_time - start_time )) <= 0 ) {
468 #endif
469 rc = 0; /* timed out */
470 LDAP_SET_LDERRNO( ld, LDAP_TIMEOUT, NULL,
471 NULL );
472 break;
475 #ifdef _SOLARIS_SDK
476 tv.tv_sec = tv_time / NANOSEC;
477 tv.tv_usec = (tv_time % NANOSEC) / (NANOSEC / MICROSEC);
478 #endif
479 LDAPDebug( LDAP_DEBUG_TRACE, "wait4msg: %ld secs to go\n",
480 tv.tv_sec, 0, 0 );
481 start_time = tmp_time;
485 return( rc );
490 * read1msg() should be called with LDAP_CONN_LOCK and LDAP_REQ_LOCK locked.
492 static int
493 read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb, LDAPConn *lc,
494 LDAPMessage **result )
496 BerElement *ber;
497 LDAPMessage *new, *l, *prev, *chainprev, *tmp;
498 ber_int_t id;
499 ber_tag_t tag;
500 ber_len_t len;
501 int terrno, lderr, foundit = 0;
502 LDAPRequest *lr;
503 int rc, has_parent, message_can_be_returned;
504 int manufactured_result = 0;
506 LDAPDebug( LDAP_DEBUG_TRACE, "read1msg\n", 0, 0, 0 );
508 message_can_be_returned = 1; /* the usual case... */
511 * if we are not already in the midst of reading a message, allocate
512 * a ber that is associated with this connection
514 if ( lc->lconn_ber == NULLBER && nsldapi_alloc_ber_with_options( ld,
515 &lc->lconn_ber ) != LDAP_SUCCESS ) {
516 return( -1 );
520 * ber_get_next() doesn't set errno on EOF, so we pre-set it to
521 * zero to avoid getting tricked by leftover "EAGAIN" errors
523 LDAP_SET_ERRNO( ld, 0 );
525 /* get the next message */
526 if ( (tag = ber_get_next( sb, &len, lc->lconn_ber ))
527 != LDAP_TAG_MESSAGE ) {
528 terrno = LDAP_GET_ERRNO( ld );
529 if ( terrno == EWOULDBLOCK || terrno == EAGAIN ) {
530 return( -2 ); /* try again */
532 LDAP_SET_LDERRNO( ld, (tag == LBER_DEFAULT ? LDAP_SERVER_DOWN :
533 LDAP_LOCAL_ERROR), NULL, NULL );
534 if ( tag == LBER_DEFAULT ) {
535 nsldapi_connection_lost_nolock( ld, sb );
537 return( -1 );
541 * Since we have received a complete message now, we pull this ber
542 * out of the connection structure and never read into it again.
544 ber = lc->lconn_ber;
545 lc->lconn_ber = NULLBER;
547 /* message id */
548 if ( ber_get_int( ber, &id ) == LBER_ERROR ) {
549 LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
550 return( -1 );
553 /* if it's been abandoned, toss it */
554 if ( ldap_abandoned( ld, (int)id ) ) {
555 ber_free( ber, 1 );
556 return( -2 ); /* continue looking */
559 if ( id == LDAP_RES_UNSOLICITED ) {
560 lr = NULL;
561 } else if (( lr = nsldapi_find_request_by_msgid( ld, id )) == NULL ) {
562 LDAPDebug( LDAP_DEBUG_ANY,
563 "no request for response with msgid %ld (tossing)\n",
564 id, 0, 0 );
565 ber_free( ber, 1 );
566 return( -2 ); /* continue looking */
569 /* the message type */
570 if ( (tag = ber_peek_tag( ber, &len )) == LBER_ERROR ) {
571 LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
572 return( -1 );
574 LDAPDebug( LDAP_DEBUG_TRACE, "got %s msgid %ld, original id %d\n",
575 ( tag == LDAP_RES_SEARCH_ENTRY ) ? "ENTRY" :
576 ( tag == LDAP_RES_SEARCH_REFERENCE ) ? "REFERENCE" : "RESULT", id,
577 ( lr == NULL ) ? id : lr->lr_origid );
579 if ( lr != NULL ) {
580 id = lr->lr_origid;
581 lr->lr_res_msgtype = tag;
583 rc = -2; /* default is to keep looking (no response found) */
585 if ( id != LDAP_RES_UNSOLICITED && ( tag == LDAP_RES_SEARCH_REFERENCE ||
586 tag != LDAP_RES_SEARCH_ENTRY )) {
587 int refchasing, reftotal, simple_request = 0;
589 check_for_refs( ld, lr, ber, lc->lconn_version, &reftotal,
590 &refchasing );
592 if ( refchasing > 0 || lr->lr_outrefcnt > 0 ) {
594 * we're chasing one or more new refs...
596 ber_free( ber, 1 );
597 ber = NULLBER;
598 lr->lr_status = LDAP_REQST_CHASINGREFS;
599 message_can_be_returned = 0;
601 } else if ( tag != LDAP_RES_SEARCH_REFERENCE ) {
603 * this request is complete...
605 has_parent = ( lr->lr_parent != NULL );
607 if ( lr->lr_outrefcnt <= 0 && !has_parent ) {
608 /* request without any refs */
609 simple_request = ( reftotal == 0 );
613 * If this is not a child request and it is a bind
614 * request, reset the connection's bind DN and
615 * status based on the result of the operation.
617 if ( !has_parent &&
618 LDAP_RES_BIND == lr->lr_res_msgtype &&
619 lr->lr_conn != NULL ) {
620 if ( lr->lr_conn->lconn_binddn != NULL ) {
621 NSLDAPI_FREE(
622 lr->lr_conn->lconn_binddn );
624 if ( LDAP_SUCCESS == nsldapi_parse_result( ld,
625 lr->lr_res_msgtype, ber, &lderr, NULL,
626 NULL, NULL, NULL )
627 && LDAP_SUCCESS == lderr ) {
628 lr->lr_conn->lconn_bound = 1;
629 lr->lr_conn->lconn_binddn =
630 lr->lr_binddn;
631 lr->lr_binddn = NULL;
632 } else {
633 lr->lr_conn->lconn_bound = 0;
634 lr->lr_conn->lconn_binddn = NULL;
639 * if this response is to a child request, we toss
640 * the message contents and just merge error info.
641 * into the parent.
643 if ( has_parent ) {
644 ber_free( ber, 1 );
645 ber = NULLBER;
647 while ( lr->lr_parent != NULL ) {
648 merge_error_info( ld, lr->lr_parent, lr );
650 lr = lr->lr_parent;
651 if ( --lr->lr_outrefcnt > 0 ) {
652 break; /* not completely done yet */
657 * we recognize a request as complete when:
658 * 1) it has no outstanding referrals
659 * 2) it is not a child request
660 * 3) we have received a result for the request (i.e.,
661 * something other than an entry or a reference).
663 if ( lr->lr_outrefcnt <= 0 && lr->lr_parent == NULL &&
664 lr->lr_res_msgtype != LDAP_RES_SEARCH_ENTRY &&
665 lr->lr_res_msgtype != LDAP_RES_SEARCH_REFERENCE ) {
666 id = lr->lr_msgid;
667 tag = lr->lr_res_msgtype;
668 LDAPDebug( LDAP_DEBUG_TRACE,
669 "request %ld done\n", id, 0, 0 );
670 LDAPDebug( LDAP_DEBUG_TRACE,
671 "res_errno: %d, res_error: <%s>, res_matched: <%s>\n",
672 lr->lr_res_errno, lr->lr_res_error ? lr->lr_res_error : "",
673 lr->lr_res_matched ? lr->lr_res_matched : "" );
674 if ( !simple_request ) {
675 if ( ber != NULLBER ) {
676 ber_free( ber, 1 );
677 ber = NULLBER;
679 if ( build_result_ber( ld, &ber, lr )
680 != LDAP_SUCCESS ) {
681 rc = -1; /* fatal error */
682 } else {
683 manufactured_result = 1;
687 nsldapi_free_request( ld, lr, 1 );
688 } else {
689 message_can_be_returned = 0;
694 if ( ber == NULLBER ) {
695 return( rc );
698 /* make a new ldap message */
699 if ( (new = (LDAPMessage*)NSLDAPI_CALLOC( 1, sizeof(struct ldapmsg) ))
700 == NULL ) {
701 LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
702 return( -1 );
704 new->lm_msgid = (int)id;
705 new->lm_msgtype = tag;
706 new->lm_ber = ber;
709 * if this is a search entry or if this request is complete (i.e.,
710 * there are no outstanding referrals) then add to cache and check
711 * to see if we should return this to the caller right away or not.
713 if ( message_can_be_returned ) {
714 if ( ld->ld_cache_on ) {
715 nsldapi_add_result_to_cache( ld, new );
718 if ( msgid == LDAP_RES_ANY || id == msgid ) {
719 if ( new->lm_msgtype == LDAP_RES_SEARCH_RESULT ) {
721 * return the first response we have for this
722 * search request later (possibly an entire
723 * chain of messages).
725 foundit = 1;
726 } else if ( all == 0
727 || (new->lm_msgtype != LDAP_RES_SEARCH_REFERENCE
728 && new->lm_msgtype != LDAP_RES_SEARCH_ENTRY) ) {
729 *result = new;
730 LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL,
731 NULL );
732 return( tag );
738 * if not, we must add it to the list of responses. if
739 * the msgid is already there, it must be part of an existing
740 * search response.
743 prev = NULL;
744 LDAP_MUTEX_LOCK( ld, LDAP_RESP_LOCK );
745 for ( l = ld->ld_responses; l != NULL; l = l->lm_next ) {
746 if ( l->lm_msgid == new->lm_msgid )
747 break;
748 prev = l;
751 /* not part of an existing search response */
752 if ( l == NULL ) {
753 if ( foundit ) {
754 LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
755 *result = new;
756 LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, NULL );
757 return( tag );
760 new->lm_next = ld->ld_responses;
761 ld->ld_responses = new;
762 LDAPDebug( LDAP_DEBUG_TRACE,
763 "adding new response id %d type %d (looking for id %d)\n",
764 new->lm_msgid, new->lm_msgtype, msgid );
765 LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
766 if( message_can_be_returned )
767 POST( ld, new->lm_msgid, new );
768 return( -2 ); /* continue looking */
771 LDAPDebug( LDAP_DEBUG_TRACE,
772 "adding response id %d type %d (looking for id %d)\n",
773 new->lm_msgid, new->lm_msgtype, msgid );
776 * part of a search response - add to end of list of entries
778 * the first step is to find the end of the list of entries and
779 * references. after the following loop is executed, tmp points to
780 * the last entry or reference in the chain. If there are none,
781 * tmp points to the search result.
783 chainprev = NULL;
784 for ( tmp = l; tmp->lm_chain != NULL &&
785 ( tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_ENTRY
786 || tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_REFERENCE );
787 tmp = tmp->lm_chain ) {
788 chainprev = tmp;
792 * If this is a manufactured result message and a result is already
793 * queued we throw away the one that is queued and replace it with
794 * our new result. This is necessary so we don't end up returning
795 * more than one result.
797 if ( manufactured_result &&
798 tmp->lm_msgtype == LDAP_RES_SEARCH_RESULT ) {
800 * the result is the only thing in the chain... replace it.
802 new->lm_chain = tmp->lm_chain;
803 new->lm_next = tmp->lm_next;
804 if ( chainprev == NULL ) {
805 if ( prev == NULL ) {
806 ld->ld_responses = new;
807 } else {
808 prev->lm_next = new;
810 } else {
811 chainprev->lm_chain = new;
813 if ( l == tmp ) {
814 l = new;
816 ldap_msgfree( tmp );
818 } else if ( manufactured_result && tmp->lm_chain != NULL
819 && tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_RESULT ) {
821 * entries or references are also present, so the result
822 * is the next entry after tmp. replace it.
824 new->lm_chain = tmp->lm_chain->lm_chain;
825 new->lm_next = tmp->lm_chain->lm_next;
826 ldap_msgfree( tmp->lm_chain );
827 tmp->lm_chain = new;
829 } else if ( tmp->lm_msgtype == LDAP_RES_SEARCH_RESULT ) {
831 * the result is the only thing in the chain... add before it.
833 new->lm_chain = tmp;
834 if ( chainprev == NULL ) {
835 if ( prev == NULL ) {
836 ld->ld_responses = new;
837 } else {
838 prev->lm_next = new;
840 } else {
841 chainprev->lm_chain = new;
843 if ( l == tmp ) {
844 l = new;
847 } else {
849 * entries and/or references are present... add to the end
850 * of the entry/reference part of the chain.
852 new->lm_chain = tmp->lm_chain;
853 tmp->lm_chain = new;
857 * return the first response or the whole chain if that's what
858 * we were looking for....
860 if ( foundit ) {
861 if ( all == 0 && l->lm_chain != NULL ) {
863 * only return the first response in the chain
865 if ( prev == NULL ) {
866 ld->ld_responses = l->lm_chain;
867 } else {
868 prev->lm_next = l->lm_chain;
870 l->lm_chain = NULL;
871 tag = l->lm_msgtype;
872 } else {
874 * return all of the responses (may be a chain)
876 if ( prev == NULL ) {
877 ld->ld_responses = l->lm_next;
878 } else {
879 prev->lm_next = l->lm_next;
882 *result = l;
883 LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
884 LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, NULL );
885 return( tag );
887 LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
888 return( -2 ); /* continue looking */
893 * check for LDAPv2+ (UMich extension) or LDAPv3 referrals or references
894 * errors are merged in "lr".
896 static void
897 check_for_refs( LDAP *ld, LDAPRequest *lr, BerElement *ber,
898 int ldapversion, int *totalcountp, int *chasingcountp )
900 int err, origerr;
901 char *errstr, *matcheddn, **v3refs;
903 LDAPDebug( LDAP_DEBUG_TRACE, "check_for_refs\n", 0, 0, 0 );
905 *chasingcountp = *totalcountp = 0;
907 if ( ldapversion < LDAP_VERSION2 || ( lr->lr_parent == NULL
908 && ( ld->ld_options & LDAP_BITOPT_REFERRALS ) == 0 )) {
909 /* referrals are not supported or are disabled */
910 return;
913 if ( lr->lr_res_msgtype == LDAP_RES_SEARCH_REFERENCE ) {
914 err = nsldapi_parse_reference( ld, ber, &v3refs, NULL );
915 origerr = LDAP_REFERRAL; /* a small lie... */
916 matcheddn = errstr = NULL;
917 } else {
918 err = nsldapi_parse_result( ld, lr->lr_res_msgtype, ber,
919 &origerr, &matcheddn, &errstr, &v3refs, NULL );
922 if ( err != LDAP_SUCCESS ) {
923 /* parse failed */
924 return;
927 if ( origerr == LDAP_REFERRAL ) { /* ldapv3 */
928 if ( v3refs != NULL ) {
929 err = nsldapi_chase_v3_refs( ld, lr, v3refs,
930 ( lr->lr_res_msgtype == LDAP_RES_SEARCH_REFERENCE ),
931 totalcountp, chasingcountp );
932 ldap_value_free( v3refs );
934 } else if ( ldapversion == LDAP_VERSION2
935 && origerr != LDAP_SUCCESS ) {
936 /* referrals may be present in the error string */
937 err = nsldapi_chase_v2_referrals( ld, lr, &errstr,
938 totalcountp, chasingcountp );
941 /* set LDAP errno, message, and matched string appropriately */
942 if ( lr->lr_res_error != NULL ) {
943 NSLDAPI_FREE( lr->lr_res_error );
945 lr->lr_res_error = errstr;
947 if ( lr->lr_res_matched != NULL ) {
948 NSLDAPI_FREE( lr->lr_res_matched );
950 lr->lr_res_matched = matcheddn;
952 if ( err == LDAP_SUCCESS && ( *chasingcountp == *totalcountp )) {
953 if ( *totalcountp > 0 && ( origerr == LDAP_PARTIAL_RESULTS
954 || origerr == LDAP_REFERRAL )) {
955 /* substitute success for referral error codes */
956 lr->lr_res_errno = LDAP_SUCCESS;
957 } else {
958 /* preserve existing non-referral error code */
959 lr->lr_res_errno = origerr;
961 } else if ( err != LDAP_SUCCESS ) {
962 /* error occurred while trying to chase referrals */
963 lr->lr_res_errno = err;
964 } else {
965 /* some referrals were not recognized */
966 lr->lr_res_errno = ( ldapversion == LDAP_VERSION2 )
967 ? LDAP_PARTIAL_RESULTS : LDAP_REFERRAL;
970 LDAPDebug( LDAP_DEBUG_TRACE,
971 "check_for_refs: new result: msgid %d, res_errno %d, ",
972 lr->lr_msgid, lr->lr_res_errno, 0 );
973 LDAPDebug( LDAP_DEBUG_TRACE, " res_error <%s>, res_matched <%s>\n",
974 lr->lr_res_error ? lr->lr_res_error : "",
975 lr->lr_res_matched ? lr->lr_res_matched : "", 0 );
976 LDAPDebug( LDAP_DEBUG_TRACE,
977 "check_for_refs: %d new refs(s); chasing %d of them\n",
978 *totalcountp, *chasingcountp, 0 );
982 /* returns an LDAP error code and also sets it in LDAP * */
983 static int
984 build_result_ber( LDAP *ld, BerElement **berp, LDAPRequest *lr )
986 ber_len_t len;
987 ber_int_t along;
988 BerElement *ber;
989 int err;
991 if (( err = nsldapi_alloc_ber_with_options( ld, &ber ))
992 != LDAP_SUCCESS ) {
993 return( err );
995 *berp = ber;
996 if ( ber_printf( ber, "{it{ess}}", lr->lr_msgid,
997 (long)lr->lr_res_msgtype, lr->lr_res_errno,
998 lr->lr_res_matched ? lr->lr_res_matched : "",
999 lr->lr_res_error ? lr->lr_res_error : "" ) == -1 ) {
1000 return( LDAP_ENCODING_ERROR );
1003 ber_reset( ber, 1 );
1004 if ( ber_skip_tag( ber, &len ) == LBER_ERROR ||
1005 ber_get_int( ber, &along ) == LBER_ERROR ||
1006 ber_peek_tag( ber, &len ) == LBER_ERROR ) {
1007 return( LDAP_DECODING_ERROR );
1010 return( LDAP_SUCCESS );
1014 static void
1015 merge_error_info( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr )
1018 * Merge error information in "lr" with "parentr" error code and string.
1020 if ( lr->lr_res_errno == LDAP_PARTIAL_RESULTS ) {
1021 parentr->lr_res_errno = lr->lr_res_errno;
1022 if ( lr->lr_res_error != NULL ) {
1023 (void)nsldapi_append_referral( ld, &parentr->lr_res_error,
1024 lr->lr_res_error );
1026 } else if ( lr->lr_res_errno != LDAP_SUCCESS &&
1027 parentr->lr_res_errno == LDAP_SUCCESS ) {
1028 parentr->lr_res_errno = lr->lr_res_errno;
1029 if ( parentr->lr_res_error != NULL ) {
1030 NSLDAPI_FREE( parentr->lr_res_error );
1032 parentr->lr_res_error = lr->lr_res_error;
1033 lr->lr_res_error = NULL;
1034 if ( NAME_ERROR( lr->lr_res_errno )) {
1035 if ( parentr->lr_res_matched != NULL ) {
1036 NSLDAPI_FREE( parentr->lr_res_matched );
1038 parentr->lr_res_matched = lr->lr_res_matched;
1039 lr->lr_res_matched = NULL;
1043 LDAPDebug( LDAP_DEBUG_TRACE, "merged parent (id %d) error info: ",
1044 parentr->lr_msgid, 0, 0 );
1045 LDAPDebug( LDAP_DEBUG_TRACE, "result lderrno %d, error <%s>, matched <%s>\n",
1046 parentr->lr_res_errno, parentr->lr_res_error ?
1047 parentr->lr_res_error : "", parentr->lr_res_matched ?
1048 parentr->lr_res_matched : "" );
1051 #if defined( CLDAP )
1052 #if !defined( macintosh ) && !defined( DOS ) && !defined( _WINDOWS ) && !defined(XP_OS2)
1053 /* XXXmcs: was revised to support extended I/O callbacks but never compiled! */
1054 static int
1055 cldap_select1( LDAP *ld, struct timeval *timeout )
1057 int rc;
1058 static int tblsize = 0;
1059 NSLDAPIIOStatus *iosp = ld->ld_iostatus;
1061 if ( tblsize == 0 ) {
1062 #ifdef USE_SYSCONF
1063 tblsize = sysconf( _SC_OPEN_MAX );
1064 #else /* USE_SYSCONF */
1065 tblsize = getdtablesize();
1066 #endif /* USE_SYSCONF */
1069 if ( tblsize >= FD_SETSIZE ) {
1071 * clamp value so we don't overrun the fd_set structure
1073 tblsize = FD_SETSIZE - 1;
1076 if ( NSLDAPI_IOSTATUS_TYPE_OSNATIVE == iosp->ios_type ) {
1077 fd_set readfds;
1079 FD_ZERO( &readfds );
1080 FD_SET( ld->ld_sbp->sb_sd, &readfds );
1082 /* XXXmcs: UNIX platforms should use poll() */
1083 rc = select( tblsize, &readfds, 0, 0, timeout ) );
1085 } else if ( NSLDAPI_IOSTATUS_TYPE_CALLBACK == iosp->ios_type ) {
1086 LDAP_X_PollFD pollfds[ 1 ];
1088 pollfds[0].lpoll_fd = ld->ld_sbp->sb_sd;
1089 pollfds[0].lpoll_arg = ld->ld_sbp->sb_arg;
1090 pollfds[0].lpoll_events = LDAP_X_POLLIN;
1091 pollfds[0].lpoll_revents = 0;
1092 rc = ld->ld_extpoll_fn( pollfds, 1, nsldapi_tv2ms( timeout ),
1093 ld->ld_ext_session_arg );
1094 } else {
1095 LDAPDebug( LDAP_DEBUG_ANY,
1096 "nsldapi_iostatus_poll: unknown I/O type %d\n",
1097 rc = 0; /* simulate a timeout (what else to do?) */
1100 return( rc );
1102 #endif /* !macintosh */
1105 #ifdef macintosh
1106 static int
1107 cldap_select1( LDAP *ld, struct timeval *timeout )
1109 /* XXXmcs: needs to be revised to support I/O callbacks */
1110 return( tcpselect( ld->ld_sbp->sb_sd, timeout ));
1112 #endif /* macintosh */
1115 #if (defined( DOS ) && defined( WINSOCK )) || defined( _WINDOWS ) || defined(XP_OS2)
1116 /* XXXmcs: needs to be revised to support extended I/O callbacks */
1117 static int
1118 cldap_select1( LDAP *ld, struct timeval *timeout )
1120 fd_set readfds;
1121 int rc;
1123 FD_ZERO( &readfds );
1124 FD_SET( ld->ld_sbp->sb_sd, &readfds );
1126 if ( NSLDAPI_IO_TYPE_STANDARD == ld->ldiou_type &&
1127 NULL != ld->ld_select_fn ) {
1128 rc = ld->ld_select_fn( 1, &readfds, 0, 0, timeout );
1129 } else if ( NSLDAPI_IO_TYPE_EXTENDED == ld->ldiou_type &&
1130 NULL != ld->ld_extselect_fn ) {
1131 rc = ld->ld_extselect_fn( ld->ld_ext_session_arg, 1, &readfds, 0,
1132 0, timeout ) );
1133 } else {
1134 /* XXXmcs: UNIX platforms should use poll() */
1135 rc = select( 1, &readfds, 0, 0, timeout ) );
1138 return( rc == SOCKET_ERROR ? -1 : rc );
1140 #endif /* WINSOCK || _WINDOWS */
1141 #endif /* CLDAP */
1144 LDAP_CALL
1145 ldap_msgfree( LDAPMessage *lm )
1147 LDAPMessage *next;
1148 int type = 0;
1150 LDAPDebug( LDAP_DEBUG_TRACE, "ldap_msgfree\n", 0, 0, 0 );
1152 for ( ; lm != NULL; lm = next ) {
1153 next = lm->lm_chain;
1154 type = lm->lm_msgtype;
1155 ber_free( lm->lm_ber, 1 );
1156 NSLDAPI_FREE( (char *) lm );
1159 return( type );
1163 * ldap_msgdelete - delete a message. It returns:
1164 * 0 if the entire message was deleted
1165 * -1 if the message was not found, or only part of it was found
1168 ldap_msgdelete( LDAP *ld, int msgid )
1170 LDAPMessage *lm, *prev;
1171 int msgtype;
1173 LDAPDebug( LDAP_DEBUG_TRACE, "ldap_msgdelete\n", 0, 0, 0 );
1175 if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
1176 return( -1 ); /* punt */
1179 prev = NULL;
1180 LDAP_MUTEX_LOCK( ld, LDAP_RESP_LOCK );
1181 for ( lm = ld->ld_responses; lm != NULL; lm = lm->lm_next ) {
1182 if ( lm->lm_msgid == msgid )
1183 break;
1184 prev = lm;
1187 if ( lm == NULL )
1189 LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
1190 return( -1 );
1193 if ( prev == NULL )
1194 ld->ld_responses = lm->lm_next;
1195 else
1196 prev->lm_next = lm->lm_next;
1197 LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
1199 msgtype = ldap_msgfree( lm );
1200 if ( msgtype == LDAP_RES_SEARCH_ENTRY
1201 || msgtype == LDAP_RES_SEARCH_REFERENCE ) {
1202 return( -1 );
1205 return( 0 );
1210 * return 1 if message msgid is waiting to be abandoned, 0 otherwise
1212 static int
1213 ldap_abandoned( LDAP *ld, int msgid )
1215 int i;
1217 LDAP_MUTEX_LOCK( ld, LDAP_ABANDON_LOCK );
1218 if ( ld->ld_abandoned == NULL )
1220 LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
1221 return( 0 );
1224 for ( i = 0; ld->ld_abandoned[i] != -1; i++ )
1225 if ( ld->ld_abandoned[i] == msgid )
1227 LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
1228 return( 1 );
1231 LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
1232 return( 0 );
1236 static int
1237 ldap_mark_abandoned( LDAP *ld, int msgid )
1239 int i;
1241 LDAP_MUTEX_LOCK( ld, LDAP_ABANDON_LOCK );
1242 if ( ld->ld_abandoned == NULL )
1244 LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
1245 return( -1 );
1248 for ( i = 0; ld->ld_abandoned[i] != -1; i++ )
1249 if ( ld->ld_abandoned[i] == msgid )
1250 break;
1252 if ( ld->ld_abandoned[i] == -1 )
1254 LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
1255 return( -1 );
1258 for ( ; ld->ld_abandoned[i] != -1; i++ ) {
1259 ld->ld_abandoned[i] = ld->ld_abandoned[i + 1];
1262 LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
1263 return( 0 );
1267 #ifdef CLDAP
1269 cldap_getmsg( LDAP *ld, struct timeval *timeout, BerElement **ber )
1271 int rc;
1272 ber_tag_t tag;
1273 ber_len_t len;
1275 if ( ld->ld_sbp->sb_ber.ber_ptr >= ld->ld_sbp->sb_ber.ber_end ) {
1276 rc = cldap_select1( ld, timeout );
1277 if ( rc == -1 || rc == 0 ) {
1278 LDAP_SET_LDERRNO( ld, (rc == -1 ? LDAP_SERVER_DOWN :
1279 LDAP_TIMEOUT), NULL, NULL );
1280 return( rc );
1284 /* get the next message */
1285 if ( (tag = ber_get_next( ld->ld_sbp, &len, ber ))
1286 != LDAP_TAG_MESSAGE ) {
1287 LDAP_SET_LDERRNO( ld, (tag == LBER_DEFAULT ? LDAP_SERVER_DOWN :
1288 LDAP_LOCAL_ERROR), NULL, NULL );
1289 return( -1 );
1292 return( tag );
1294 #endif /* CLDAP */
1297 nsldapi_post_result( LDAP *ld, int msgid, LDAPMessage *result )
1299 LDAPPend *lp;
1301 LDAPDebug( LDAP_DEBUG_TRACE,
1302 "nsldapi_post_result(ld=0x%x, msgid=%d, result=0x%x)\n",
1303 ld, msgid, result );
1304 LDAP_MUTEX_LOCK( ld, LDAP_PEND_LOCK );
1305 if( msgid == LDAP_RES_ANY ) {
1307 * Look for any pending request for which someone is waiting.
1309 for( lp = ld->ld_pend; lp != NULL; lp = lp->lp_next )
1311 if ( lp->lp_sema != NULL ) {
1312 break;
1316 * If we did't find a pending request, lp is NULL at this
1317 * point, and we will leave this function without doing
1318 * anything more -- which is exactly what we want to do.
1321 else
1324 * Look for a pending request specific to this message id
1326 for( lp = ld->ld_pend; lp != NULL; lp = lp->lp_next )
1328 if( lp->lp_msgid == msgid )
1329 break;
1332 if( lp == NULL )
1335 * No pending requests for this response... append to
1336 * our pending result list.
1338 LDAPPend *newlp;
1339 newlp = (LDAPPend *)NSLDAPI_CALLOC( 1,
1340 sizeof( LDAPPend ));
1341 if( newlp == NULL )
1343 LDAP_MUTEX_UNLOCK( ld, LDAP_PEND_LOCK );
1344 LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL,
1345 NULL );
1346 return (-1);
1348 newlp->lp_msgid = msgid;
1349 newlp->lp_result = result;
1350 link_pend( ld, newlp );
1355 if( lp != NULL )
1358 * Wake up a thread that is waiting for this result.
1360 lp->lp_msgid = msgid;
1361 lp->lp_result = result;
1362 LDAP_SEMA_POST( ld, lp );
1365 LDAP_MUTEX_UNLOCK( ld, LDAP_PEND_LOCK );
1366 return (0);
1369 static void
1370 link_pend( LDAP *ld, LDAPPend *lp )
1372 if (( lp->lp_next = ld->ld_pend ) != NULL )
1374 lp->lp_next->lp_prev = lp;
1376 ld->ld_pend = lp;
1377 lp->lp_prev = NULL;
1380 #if 0 /* these functions are no longer used */
1381 static void
1382 unlink_pend( LDAP *ld, LDAPPend *lp )
1384 if ( lp->lp_prev == NULL ) {
1385 ld->ld_pend = lp->lp_next;
1386 } else {
1387 lp->lp_prev->lp_next = lp->lp_next;
1390 if ( lp->lp_next != NULL ) {
1391 lp->lp_next->lp_prev = lp->lp_prev;
1395 static int
1396 unlink_msg( LDAP *ld, int msgid, int all )
1398 int rc;
1399 LDAPMessage *lm, *lastlm, *nextlm;
1401 lastlm = NULL;
1402 LDAP_MUTEX_LOCK( ld, LDAP_RESP_LOCK );
1403 for ( lm = ld->ld_responses; lm != NULL; lm = nextlm )
1405 nextlm = lm->lm_next;
1407 if ( lm->lm_msgid == msgid )
1409 LDAPMessage *tmp;
1411 if ( all == 0
1412 || (lm->lm_msgtype != LDAP_RES_SEARCH_RESULT
1413 && lm->lm_msgtype != LDAP_RES_SEARCH_REFERENCE
1414 && lm->lm_msgtype != LDAP_RES_SEARCH_ENTRY) )
1415 break;
1417 for ( tmp = lm; tmp != NULL; tmp = tmp->lm_chain ) {
1418 if ( tmp->lm_msgtype == LDAP_RES_SEARCH_RESULT )
1419 break;
1421 if( tmp != NULL )
1422 break;
1424 lastlm = lm;
1427 if( lm != NULL )
1430 if ( all == 0 )
1432 if ( lm->lm_chain == NULL )
1434 if ( lastlm == NULL )
1435 ld->ld_responses = lm->lm_next;
1436 else
1437 lastlm->lm_next = lm->lm_next;
1439 else
1441 if ( lastlm == NULL )
1443 ld->ld_responses = lm->lm_chain;
1444 ld->ld_responses->lm_next = lm->lm_next;
1446 else
1448 lastlm->lm_next = lm->lm_chain;
1449 lastlm->lm_next->lm_next = lm->lm_next;
1453 else
1455 if ( lastlm == NULL )
1456 ld->ld_responses = lm->lm_next;
1457 else
1458 lastlm->lm_next = lm->lm_next;
1461 if ( all == 0 )
1462 lm->lm_chain = NULL;
1463 lm->lm_next = NULL;
1464 rc = lm->lm_msgtype;
1466 else
1468 rc = -2;
1470 LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
1471 return ( rc );
1473 #endif /* 0 */