diff options
Diffstat (limited to 'ldap/c-sdk/libraries/libldap/result.c')
-rw-r--r-- | ldap/c-sdk/libraries/libldap/result.c | 1473 |
1 files changed, 0 insertions, 1473 deletions
diff --git a/ldap/c-sdk/libraries/libldap/result.c b/ldap/c-sdk/libraries/libldap/result.c deleted file mode 100644 index 59c15f811..000000000 --- a/ldap/c-sdk/libraries/libldap/result.c +++ /dev/null @@ -1,1473 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Mozilla Communicator client code, released - * March 31, 1998. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1998-1999 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ -/* - * Copyright (c) 1990 Regents of the University of Michigan. - * All rights reserved. - */ -/* - * result.c - wait for an ldap result - */ - -#if 0 -#ifndef lint -static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n"; -#endif -#endif - -#include "ldap-int.h" - -/* - * Special return values used by some functions (wait4msg() and read1msg()). - */ -#define NSLDAPI_RESULT_TIMEOUT 0 -#define NSLDAPI_RESULT_ERROR (-1) -#define NSLDAPI_RESULT_NOT_FOUND (-2) - -static int check_response_queue( LDAP *ld, int msgid, int all, - int do_abandon_check, LDAPMessage **result ); -static int ldap_abandoned( LDAP *ld, int msgid ); -static int ldap_mark_abandoned( LDAP *ld, int msgid ); -static int wait4msg( LDAP *ld, int msgid, int all, int unlock_permitted, - struct timeval *timeout, LDAPMessage **result ); -static int read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb, LDAPConn **lcp, - LDAPMessage **result ); -static void check_for_refs( LDAP *ld, LDAPRequest *lr, BerElement *ber, - int ldapversion, int *totalcountp, int *chasingcountp ); -static int build_result_ber( LDAP *ld, BerElement **berp, LDAPRequest *lr ); -static void merge_error_info( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr ); -#if defined( CLDAP ) -static int cldap_select1( LDAP *ld, struct timeval *timeout ); -#endif -static void link_pend( LDAP *ld, LDAPPend *lp ); - -/* - * ldap_result - wait for an ldap result response to a message from the - * ldap server. If msgid is -1, any message will be accepted, otherwise - * ldap_result will wait for a response with msgid. If all is 0 the - * first message with id msgid will be accepted, otherwise, ldap_result - * will wait for all responses with id msgid and then return a pointer to - * the entire list of messages. This is only useful for search responses, - * which can be of two message types (zero or more entries, followed by an - * ldap result). The type of the first message received is returned. - * When waiting, any messages that have been abandoned are discarded. - * - * Example: - * ldap_result( s, msgid, all, timeout, result ) - */ -int -LDAP_CALL -ldap_result( - LDAP *ld, - int msgid, - int all, - struct timeval *timeout, - LDAPMessage **result -) -{ - int rc; - - LDAPDebug( LDAP_DEBUG_TRACE, "ldap_result\n", 0, 0, 0 ); - - if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) { - return( -1 ); /* punt */ - } - - LDAP_MUTEX_LOCK( ld, LDAP_RESULT_LOCK ); - - rc = nsldapi_result_nolock(ld, msgid, all, 1, timeout, result); - - LDAP_MUTEX_UNLOCK( ld, LDAP_RESULT_LOCK ); - - return( rc ); -} - - -int -nsldapi_result_nolock( LDAP *ld, int msgid, int all, int unlock_permitted, - struct timeval *timeout, LDAPMessage **result ) -{ - int rc; - - LDAPDebug( LDAP_DEBUG_TRACE, - "nsldapi_result_nolock (msgid=%d, all=%d)\n", msgid, all, 0 ); - - /* - * First, look through the list of responses we have received on - * this association and see if the response we're interested in - * is there. If it is, return it. If not, call wait4msg() to - * wait until it arrives or timeout occurs. - */ - - if ( result == NULL ) { - LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL ); - return( -1 ); - } - - if ( check_response_queue( ld, msgid, all, 1, result ) != 0 ) { - LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, NULL ); - rc = (*result)->lm_msgtype; - } else { - rc = wait4msg( ld, msgid, all, unlock_permitted, timeout, - result ); - } - - /* - * XXXmcs should use cache function pointers to hook in memcache - */ - if ( ld->ld_memcache != NULL && NSLDAPI_SEARCH_RELATED_RESULT( rc ) && - !((*result)->lm_fromcache )) { - ldap_memcache_append( ld, (*result)->lm_msgid, - (all || NSLDAPI_IS_SEARCH_RESULT( rc )), *result ); - } - - return( rc ); -} - - -/* - * Look through the list of queued responses for a message that matches the - * criteria in the msgid and all parameters. msgid == LDAP_RES_ANY matches - * all ids. - * - * If an appropriate message is found, a non-zero value is returned and the - * message is dequeued and assigned to *result. - * - * If not, *result is set to NULL and this function returns 0. - */ -static int -check_response_queue( LDAP *ld, int msgid, int all, int do_abandon_check, - LDAPMessage **result ) -{ - LDAPMessage *lm, *lastlm, *nextlm; - LDAPRequest *lr; - - LDAPDebug( LDAP_DEBUG_TRACE, - "=> check_response_queue (msgid=%d, all=%d)\n", msgid, all, 0 ); - - *result = NULL; - lastlm = NULL; - LDAP_MUTEX_LOCK( ld, LDAP_RESP_LOCK ); - for ( lm = ld->ld_responses; lm != NULL; lm = nextlm ) { - nextlm = lm->lm_next; - - if ( do_abandon_check && ldap_abandoned( ld, lm->lm_msgid ) ) { - ldap_mark_abandoned( ld, lm->lm_msgid ); - - if ( lastlm == NULL ) { - ld->ld_responses = lm->lm_next; - } else { - lastlm->lm_next = nextlm; - } - - ldap_msgfree( lm ); - - continue; - } - - if ( msgid == LDAP_RES_ANY || lm->lm_msgid == msgid ) { - LDAPMessage *tmp; - - if ( all == 0 - || (lm->lm_msgtype != LDAP_RES_SEARCH_RESULT - && lm->lm_msgtype != LDAP_RES_SEARCH_REFERENCE - && lm->lm_msgtype != LDAP_RES_SEARCH_ENTRY) ) - break; - - for ( tmp = lm; tmp != NULL; tmp = tmp->lm_chain ) { - if ( tmp->lm_msgtype == LDAP_RES_SEARCH_RESULT ) - break; - } - - if ( tmp == NULL ) { - LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK ); - LDAPDebug( LDAP_DEBUG_TRACE, - "<= check_response_queue NOT FOUND\n", - 0, 0, 0 ); - return( 0 ); /* no message to return */ - } - - break; - } - lastlm = lm; - } - - /* - * if we did not find a message OR if the one we found is a result for - * a request that is still pending, return failure. - */ - if ( lm == NULL - || (( lr = nsldapi_find_request_by_msgid( ld, lm->lm_msgid )) - != NULL && lr->lr_outrefcnt > 0 )) { - LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK ); - LDAPDebug( LDAP_DEBUG_TRACE, - "<= check_response_queue NOT FOUND\n", - 0, 0, 0 ); - return( 0 ); /* no message to return */ - } - - if ( all == 0 ) { - if ( lm->lm_chain == NULL ) { - if ( lastlm == NULL ) { - ld->ld_responses = lm->lm_next; - } else { - lastlm->lm_next = lm->lm_next; - } - } else { - if ( lastlm == NULL ) { - ld->ld_responses = lm->lm_chain; - ld->ld_responses->lm_next = lm->lm_next; - } else { - lastlm->lm_next = lm->lm_chain; - lastlm->lm_next->lm_next = lm->lm_next; - } - } - } else { - if ( lastlm == NULL ) { - ld->ld_responses = lm->lm_next; - } else { - lastlm->lm_next = lm->lm_next; - } - } - - if ( all == 0 ) { - lm->lm_chain = NULL; - } - lm->lm_next = NULL; - LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK ); - - *result = lm; - LDAPDebug( LDAP_DEBUG_TRACE, - "<= check_response_queue returning msgid %d type %d\n", - lm->lm_msgid, lm->lm_msgtype, 0 ); - return( 1 ); /* a message was found and returned in *result */ -} - - -/* - * wait4msg(): Poll for incoming LDAP messages, respecting the timeout. - * - * Return values: - * > 0: message received; value is the tag of the message. - * NSLDAPI_RESULT_TIMEOUT timeout exceeded. - * NSLDAPI_RESULT_ERROR fatal error occurred such as connection closed. - */ -static int -wait4msg( LDAP *ld, int msgid, int all, int unlock_permitted, - struct timeval *timeout, LDAPMessage **result ) -{ - int err, rc = NSLDAPI_RESULT_NOT_FOUND, msgfound; - struct timeval tv, *tvp; - long start_time = 0, tmp_time; - LDAPConn *lc, *nextlc; - /* lr points to the specific request we are waiting for, if any */ - LDAPRequest *lr = NULL; - -#ifdef LDAP_DEBUG - if ( timeout == NULL ) { - LDAPDebug( LDAP_DEBUG_TRACE, "wait4msg (infinite timeout)\n", - 0, 0, 0 ); - } else { - LDAPDebug( LDAP_DEBUG_TRACE, "wait4msg (timeout %ld sec, %ld usec)\n", - timeout->tv_sec, (long) timeout->tv_usec, 0 ); - } -#endif /* LDAP_DEBUG */ - - /* check the cache */ - if ( ld->ld_cache_on && ld->ld_cache_result != NULL ) { - /* if ( unlock_permitted ) LDAP_MUTEX_UNLOCK( ld ); */ - LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK ); - rc = (ld->ld_cache_result)( ld, msgid, all, timeout, result ); - LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK ); - /* if ( unlock_permitted ) LDAP_MUTEX_LOCK( ld ); */ - if ( rc != NSLDAPI_RESULT_TIMEOUT ) { - return( rc ); - } - if ( ld->ld_cache_strategy == LDAP_CACHE_LOCALDB ) { - LDAP_SET_LDERRNO( ld, LDAP_TIMEOUT, NULL, NULL ); - return( NSLDAPI_RESULT_TIMEOUT ); - } - } - - /* - * if we are looking for a specific msgid, check to see if it is - * associated with a dead connection and return an error if so. - */ - if ( msgid != LDAP_RES_ANY && msgid != LDAP_RES_UNSOLICITED ) { - LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK ); - if (( lr = nsldapi_find_request_by_msgid( ld, msgid )) - == NULL ) { - LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK ); - LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, - nsldapi_strdup( "unknown message id" )); - return( NSLDAPI_RESULT_ERROR ); /* could not find request for msgid */ - } - if ( lr->lr_conn != NULL && - lr->lr_conn->lconn_status == LDAP_CONNST_DEAD ) { - nsldapi_free_request( ld, lr, 1 ); - LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK ); - LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN, NULL, NULL ); - return( NSLDAPI_RESULT_ERROR ); /* connection dead */ - } - LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK ); - } - - if ( timeout == NULL ) { - tvp = NULL; - } else { - tv = *timeout; - tvp = &tv; - start_time = (long)time( NULL ); - } - - rc = NSLDAPI_RESULT_NOT_FOUND; - while ( rc == NSLDAPI_RESULT_NOT_FOUND ) { - msgfound = 0; -#ifdef LDAP_DEBUG - if ( ldap_debug & LDAP_DEBUG_TRACE ) { - nsldapi_dump_connection( ld, ld->ld_conns, 1 ); - nsldapi_dump_requests_and_responses( ld ); - } -#endif /* LDAP_DEBUG */ - - /* - * Check if we have some data in a connection's BER buffer. - * If so, use it. - */ - LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK ); - LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK ); - for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) { - if ( lc->lconn_sb->sb_ber.ber_ptr < - lc->lconn_sb->sb_ber.ber_end ) { - /* read1msg() might free the connection. */ - rc = read1msg( ld, msgid, all, lc->lconn_sb, - &lc, result ); - /* Indicate to next segment that we've processed a message - (or several, via chased refs) this time around. */ - msgfound = 1; - break; - } - } - LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK ); - LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK ); - - if ( !msgfound ) { - /* - * There was no buffered data. Poll to check connection - * status (read/write readiness). - */ - err = nsldapi_iostatus_poll( ld, tvp ); - -#if defined( LDAP_DEBUG ) && !defined( macintosh ) && !defined( DOS ) - if ( err == -1 ) { - LDAPDebug( LDAP_DEBUG_TRACE, - "nsldapi_iostatus_poll returned -1: errno %d\n", - LDAP_GET_ERRNO( ld ), 0, 0 ); - } -#endif - -#if !defined( macintosh ) && !defined( DOS ) - /* - * If the restart option is enabled and the error - * was EINTR, try again. - */ - if ( err == -1 - && 0 != ( ld->ld_options & LDAP_BITOPT_RESTART ) - && LDAP_GET_ERRNO( ld ) == EINTR ) { - continue; - } -#endif - - /* - * Handle timeouts (no activity) and fatal errors. - */ - if ( err == -1 || err == 0 ) { - LDAP_SET_LDERRNO( ld, (err == -1 ? - LDAP_SERVER_DOWN : LDAP_TIMEOUT), NULL, - NULL ); - if ( err == -1 ) { - LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK ); - nsldapi_connection_lost_nolock( ld, - NULL ); - LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK ); - rc = NSLDAPI_RESULT_ERROR; - } else { - rc = NSLDAPI_RESULT_TIMEOUT; - } - return( rc ); - } - - /* - * Check each connection for interesting activity. - */ - LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK ); - LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK ); - for ( lc = ld->ld_conns; - rc == NSLDAPI_RESULT_NOT_FOUND && lc != NULL; - lc = nextlc ) { - nextlc = lc->lconn_next; - - /* - * For connections that are in the CONNECTING - * state, check for write ready (which - * indicates that the connection completed) and - * transition to the CONNECTED state. - */ - if ( lc->lconn_status == LDAP_CONNST_CONNECTING - && nsldapi_iostatus_is_write_ready( ld, - lc->lconn_sb ) ) { - lc->lconn_status = LDAP_CONNST_CONNECTED; - LDAPDebug( LDAP_DEBUG_TRACE, - "wait4msg: connection 0x%p -" - " LDAP_CONNST_CONNECTING ->" - " LDAP_CONNST_CONNECTED\n", - lc, 0, 0 ); - } - - if ( lc->lconn_status - != LDAP_CONNST_CONNECTED ) { - continue; - } - - /* - * For connections that are CONNECTED, check - * for read ready (which indicates that data - * from server is available), and, for - * connections with associated requests that - * have not yet been sent, write ready (okay - * to send some data to the server). - */ - if ( nsldapi_iostatus_is_read_ready( ld, - lc->lconn_sb )) { - /* read1msg() might free the connection. */ - rc = read1msg( ld, msgid, all, - lc->lconn_sb, &lc, result ); - } - - /* - * Send pending requests if possible. If there is no lc then - * it was a child connection closed by read1msg(). - */ - if ( lc && lc->lconn_pending_requests > 0 - && nsldapi_iostatus_is_write_ready( ld, - lc->lconn_sb )) { - err = nsldapi_send_pending_requests_nolock( - ld, lc ); - if ( err == -1 && - rc == NSLDAPI_RESULT_NOT_FOUND ) { - rc = NSLDAPI_RESULT_ERROR; - } - } - - } - - LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK ); - LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK ); - } - - /* - * It is possible that recursion occurred while chasing - * referrals and as a result the message we are looking - * for may have been placed on the response queue. Look - * for it there before continuing so we don't end up - * waiting on the network for a message that we already - * received! - */ - if ( rc == NSLDAPI_RESULT_NOT_FOUND && - check_response_queue( ld, msgid, all, 0, result ) != 0 ) { - LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, NULL ); - rc = (*result)->lm_msgtype; - } - - /* - * honor the timeout if specified - */ - if ( rc == NSLDAPI_RESULT_NOT_FOUND && tvp != NULL ) { - tmp_time = (long)time( NULL ); - if (( tv.tv_sec -= ( tmp_time - start_time )) <= 0 ) { - rc = NSLDAPI_RESULT_TIMEOUT; - LDAP_SET_LDERRNO( ld, LDAP_TIMEOUT, NULL, - NULL ); - break; - } - - LDAPDebug( LDAP_DEBUG_TRACE, "wait4msg: %ld secs to go\n", - tv.tv_sec, 0, 0 ); - start_time = tmp_time; - } - } - - return( rc ); -} - - -#define NSLDAPI_REQUEST_COMPLETE( lr ) \ - ( (lr)->lr_outrefcnt <= 0 && \ - (lr)->lr_res_msgtype != LDAP_RES_SEARCH_ENTRY && \ - (lr)->lr_res_msgtype != LDAP_RES_SEARCH_REFERENCE ) - -/* - * read1msg() should be called with LDAP_CONN_LOCK and LDAP_REQ_LOCK locked. - * - * Return values: - * > 0: message received; value is the tag of the message. - * NSLDAPI_RESULT_TIMEOUT timeout exceeded. - * NSLDAPI_RESULT_ERROR fatal error occurred such as connection closed. - * NSLDAPI_RESULT_NOT_FOUND message not yet complete; keep waiting. - * - * The LDAPConn passed in my be freed by read1msg() if the reference count - * shows that it's no longer needed. - */ -static int -read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb, LDAPConn **lcp, - LDAPMessage **result ) -{ - BerElement *ber; - LDAPMessage *new, *l, *prev, *chainprev, *tmp; - ber_int_t id; - ber_tag_t tag; - ber_len_t len; - int terrno, lderr, foundit = 0; - LDAPRequest *lr; - int rc, has_parent, message_can_be_returned; - int manufactured_result = 0; - LDAPConn *lc = *lcp; - - LDAPDebug( LDAP_DEBUG_TRACE, "read1msg\n", 0, 0, 0 ); - - message_can_be_returned = 1; /* the usual case... */ - - /* - * if we are not already in the midst of reading a message, allocate - * a ber that is associated with this connection - */ - if ( lc->lconn_ber == NULLBER && nsldapi_alloc_ber_with_options( ld, - &lc->lconn_ber ) != LDAP_SUCCESS ) { - return( NSLDAPI_RESULT_ERROR ); - } - - /* - * ber_get_next() doesn't set errno on EOF, so we pre-set it to - * zero to avoid getting tricked by leftover "EAGAIN" errors - */ - LDAP_SET_ERRNO( ld, 0 ); - - /* get the next message */ - if ( (tag = ber_get_next( sb, &len, lc->lconn_ber )) - != LDAP_TAG_MESSAGE ) { - terrno = LDAP_GET_ERRNO( ld ); - if ( terrno == EWOULDBLOCK || terrno == EAGAIN ) { - return( NSLDAPI_RESULT_NOT_FOUND ); /* try again */ - } - LDAP_SET_LDERRNO( ld, (tag == LBER_DEFAULT ? LDAP_SERVER_DOWN : - LDAP_LOCAL_ERROR), NULL, NULL ); - if ( tag == LBER_DEFAULT ) { - nsldapi_connection_lost_nolock( ld, sb ); - } - return( NSLDAPI_RESULT_ERROR ); - } - - /* - * Since we have received a complete message now, we pull this ber - * out of the connection structure and never read into it again. - */ - ber = lc->lconn_ber; - lc->lconn_ber = NULLBER; - - /* message id */ - if ( ber_get_int( ber, &id ) == LBER_ERROR ) { - ber_free( ber, 1 ); - LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL ); - return( NSLDAPI_RESULT_ERROR ); - } - - /* if it's been abandoned, toss it */ - if ( ldap_abandoned( ld, (int)id ) ) { - ber_free( ber, 1 ); - return( NSLDAPI_RESULT_NOT_FOUND ); /* continue looking */ - } - - if ( id == LDAP_RES_UNSOLICITED ) { - lr = NULL; - } else if (( lr = nsldapi_find_request_by_msgid( ld, id )) == NULL ) { - LDAPDebug( LDAP_DEBUG_ANY, - "no request for response with msgid %d (tossing)\n", - id, 0, 0 ); - ber_free( ber, 1 ); - return( NSLDAPI_RESULT_NOT_FOUND ); /* continue looking */ - } - - /* the message type */ - if ( (tag = ber_peek_tag( ber, &len )) == LBER_ERROR ) { - ber_free( ber, 1 ); - LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL ); - return( NSLDAPI_RESULT_ERROR ); - } - LDAPDebug( LDAP_DEBUG_TRACE, "got %s msgid %d, original id %d\n", - ( tag == LDAP_RES_SEARCH_ENTRY ) ? "ENTRY" : - ( tag == LDAP_RES_SEARCH_REFERENCE ) ? "REFERENCE" : "RESULT", id, - ( lr == NULL ) ? id : lr->lr_origid ); - - if ( lr != NULL ) { - id = lr->lr_origid; - lr->lr_res_msgtype = tag; - } - rc = NSLDAPI_RESULT_NOT_FOUND; /* default is to keep looking (no response found) */ - - if ( id != LDAP_RES_UNSOLICITED && ( tag == LDAP_RES_SEARCH_REFERENCE || - tag != LDAP_RES_SEARCH_ENTRY )) { - int refchasing, reftotal, simple_request = 0; - LDAPControl **ctrls = NULL; - - check_for_refs( ld, lr, ber, lc->lconn_version, &reftotal, - &refchasing ); - - if ( refchasing > 0 || lr->lr_outrefcnt > 0 ) { - /* - * we're chasing one or more new refs... - */ - ber_free( ber, 1 ); - ber = NULLBER; - lr->lr_status = LDAP_REQST_CHASINGREFS; - message_can_be_returned = 0; - - } else if ( tag != LDAP_RES_SEARCH_REFERENCE ) { - /* - * this request is complete... - */ - has_parent = ( lr->lr_parent != NULL ); - - if ( lr->lr_outrefcnt <= 0 && !has_parent ) { - /* request without any refs */ - simple_request = ( reftotal == 0 ); - } - - /* - * If this is not a child request and it is a bind - * request, reset the connection's bind DN and - * status based on the result of the operation. - */ - if ( !has_parent && - LDAP_RES_BIND == lr->lr_res_msgtype && - lr->lr_conn != NULL ) { - if ( lr->lr_conn->lconn_binddn != NULL ) { - NSLDAPI_FREE( - lr->lr_conn->lconn_binddn ); - } - if ( LDAP_SUCCESS == nsldapi_parse_result( ld, - lr->lr_res_msgtype, ber, &lderr, NULL, - NULL, NULL, NULL ) - && LDAP_SUCCESS == lderr ) { - lr->lr_conn->lconn_bound = 1; - lr->lr_conn->lconn_binddn = - lr->lr_binddn; - lr->lr_binddn = NULL; - } else { - lr->lr_conn->lconn_bound = 0; - lr->lr_conn->lconn_binddn = NULL; - } - } - - /* - * if this response is to a child request, we toss - * the message contents and just merge error info. - * into the parent. - */ - if ( has_parent ) { - /* Extract any response controls from ber before ditching it */ - if( nsldapi_find_controls( ber, &ctrls ) != LDAP_SUCCESS ) { - ber_free( ber, 1 ); - LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL ); - return( NSLDAPI_RESULT_ERROR ); - } - - ber_free( ber, 1 ); - ber = NULLBER; - } - while ( lr->lr_parent != NULL ) { - merge_error_info( ld, lr->lr_parent, lr ); - - lr = lr->lr_parent; - --lr->lr_outrefcnt; - if ( !NSLDAPI_REQUEST_COMPLETE(lr)) { - break; - } - } - /* Stash response controls in original request so they can be baked - into the manufactured result message later */ - if( ctrls != NULL ) { - if( lr->lr_res_ctrls != NULL ) { - /* There are controls saved in original request already, - replace them with the new ones because we only save - the final controls received. - May want to arrange for merging intermediate response - controls into the array in the future */ - ldap_controls_free( lr->lr_res_ctrls ); - } - lr->lr_res_ctrls = ctrls; - } - - /* - * we recognize a request as fully complete when: - * 1) it is not a child request (NULL parent) - * 2) it has no outstanding referrals - * 3) we have received a result for the request (i.e., - * something other than an entry or a reference). - */ - if ( lr->lr_parent == NULL - && NSLDAPI_REQUEST_COMPLETE(lr)) { - id = lr->lr_msgid; - tag = lr->lr_res_msgtype; - LDAPDebug( LDAP_DEBUG_TRACE, - "request %d done\n", id, 0, 0 ); -LDAPDebug( LDAP_DEBUG_TRACE, -"res_errno: %d, res_error: <%s>, res_matched: <%s>\n", -lr->lr_res_errno, lr->lr_res_error ? lr->lr_res_error : "", -lr->lr_res_matched ? lr->lr_res_matched : "" ); - if ( !simple_request ) { - if ( ber != NULLBER ) { - ber_free( ber, 1 ); - ber = NULLBER; - } - if ( build_result_ber( ld, &ber, lr ) - != LDAP_SUCCESS ) { - rc = NSLDAPI_RESULT_ERROR; - } else { - manufactured_result = 1; - } - } - - nsldapi_free_request( ld, lr, 1 ); - /* Since we asked nsldapi_free_request() to free the - connection, lets make sure our callers know it's gone. */ - *lcp = NULL; - } else { - message_can_be_returned = 0; - } - } - } - - if ( ber == NULLBER ) { - return( rc ); - } - - /* make a new ldap message */ - if ( (new = (LDAPMessage*)NSLDAPI_CALLOC( 1, sizeof(struct ldapmsg) )) - == NULL ) { - LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL ); - return( NSLDAPI_RESULT_ERROR ); - } - new->lm_msgid = (int)id; - new->lm_msgtype = tag; - new->lm_ber = ber; - - /* - * if this is a search entry or if this request is complete (i.e., - * there are no outstanding referrals) then add to cache and check - * to see if we should return this to the caller right away or not. - */ - if ( message_can_be_returned ) { - if ( ld->ld_cache_on ) { - nsldapi_add_result_to_cache( ld, new ); - } - - if ( msgid == LDAP_RES_ANY || id == msgid ) { - if ( new->lm_msgtype == LDAP_RES_SEARCH_RESULT ) { - /* - * return the first response we have for this - * search request later (possibly an entire - * chain of messages). - */ - foundit = 1; - } else if ( all == 0 - || (new->lm_msgtype != LDAP_RES_SEARCH_REFERENCE - && new->lm_msgtype != LDAP_RES_SEARCH_ENTRY) ) { - *result = new; - LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, - NULL ); - return( tag ); - } - } - } - - /* - * if not, we must add it to the list of responses. if - * the msgid is already there, it must be part of an existing - * search response. - */ - - prev = NULL; - LDAP_MUTEX_LOCK( ld, LDAP_RESP_LOCK ); - for ( l = ld->ld_responses; l != NULL; l = l->lm_next ) { - if ( l->lm_msgid == new->lm_msgid ) - break; - prev = l; - } - - /* not part of an existing search response */ - if ( l == NULL ) { - if ( foundit ) { - LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK ); - *result = new; - LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, NULL ); - return( tag ); - } - - new->lm_next = ld->ld_responses; - ld->ld_responses = new; - LDAPDebug( LDAP_DEBUG_TRACE, - "adding new response id %d type %d (looking for id %d)\n", - new->lm_msgid, new->lm_msgtype, msgid ); - LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK ); - if( message_can_be_returned ) - POST( ld, new->lm_msgid, new ); - return( NSLDAPI_RESULT_NOT_FOUND ); /* continue looking */ - } - - LDAPDebug( LDAP_DEBUG_TRACE, - "adding response 0x%p - id %d type %d", - new, new->lm_msgid, new->lm_msgtype ); - LDAPDebug( LDAP_DEBUG_TRACE, " (looking for id %d)\n", msgid, 0, 0 ); - - /* - * part of a search response - add to end of list of entries - * - * the first step is to find the end of the list of entries and - * references. after the following loop is executed, tmp points to - * the last entry or reference in the chain. If there are none, - * tmp points to the search result. - */ - chainprev = NULL; - for ( tmp = l; tmp->lm_chain != NULL && - ( tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_ENTRY - || tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_REFERENCE ); - tmp = tmp->lm_chain ) { - chainprev = tmp; - } - - /* - * If this is a manufactured result message and a result is already - * queued we throw away the one that is queued and replace it with - * our new result. This is necessary so we don't end up returning - * more than one result. - */ - if ( manufactured_result && - tmp->lm_msgtype == LDAP_RES_SEARCH_RESULT ) { - /* - * the result is the only thing in the chain... replace it. - */ - new->lm_chain = tmp->lm_chain; - new->lm_next = tmp->lm_next; - if ( chainprev == NULL ) { - if ( prev == NULL ) { - ld->ld_responses = new; - } else { - prev->lm_next = new; - } - } else { - chainprev->lm_chain = new; - } - if ( l == tmp ) { - l = new; - } - ldap_msgfree( tmp ); - - } else if ( manufactured_result && tmp->lm_chain != NULL - && tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_RESULT ) { - /* - * entries or references are also present, so the result - * is the next entry after tmp. replace it. - */ - new->lm_chain = tmp->lm_chain->lm_chain; - new->lm_next = tmp->lm_chain->lm_next; - ldap_msgfree( tmp->lm_chain ); - tmp->lm_chain = new; - - } else if ( tmp->lm_msgtype == LDAP_RES_SEARCH_RESULT ) { - /* - * the result is the only thing in the chain... add before it. - */ - new->lm_chain = tmp; - if ( chainprev == NULL ) { - if ( prev == NULL ) { - ld->ld_responses = new; - } else { - prev->lm_next = new; - } - } else { - chainprev->lm_chain = new; - } - if ( l == tmp ) { - l = new; - } - - } else { - /* - * entries and/or references are present... add to the end - * of the entry/reference part of the chain. - */ - new->lm_chain = tmp->lm_chain; - tmp->lm_chain = new; - } - - /* - * return the first response or the whole chain if that's what - * we were looking for.... - */ - if ( foundit ) { - if ( all == 0 && l->lm_chain != NULL ) { - /* - * only return the first response in the chain - */ - if ( prev == NULL ) { - ld->ld_responses = l->lm_chain; - } else { - prev->lm_next = l->lm_chain; - } - l->lm_chain = NULL; - tag = l->lm_msgtype; - } else { - /* - * return all of the responses (may be a chain) - */ - if ( prev == NULL ) { - ld->ld_responses = l->lm_next; - } else { - prev->lm_next = l->lm_next; - } - } - *result = l; - LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK ); - LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, NULL ); - return( tag ); - } - LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK ); - return( NSLDAPI_RESULT_NOT_FOUND ); /* continue looking */ -} - - -/* - * check for LDAPv2+ (UMich extension) or LDAPv3 referrals or references - * errors are merged in "lr". - */ -static void -check_for_refs( LDAP *ld, LDAPRequest *lr, BerElement *ber, - int ldapversion, int *totalcountp, int *chasingcountp ) -{ - int err, origerr; - char *errstr, *matcheddn, **v3refs; - - LDAPDebug( LDAP_DEBUG_TRACE, "check_for_refs\n", 0, 0, 0 ); - - *chasingcountp = *totalcountp = 0; - - if ( ldapversion < LDAP_VERSION2 || ( lr->lr_parent == NULL - && ( ld->ld_options & LDAP_BITOPT_REFERRALS ) == 0 )) { - /* referrals are not supported or are disabled */ - return; - } - - if ( lr->lr_res_msgtype == LDAP_RES_SEARCH_REFERENCE ) { - err = nsldapi_parse_reference( ld, ber, &v3refs, NULL ); - origerr = LDAP_REFERRAL; /* a small lie... */ - matcheddn = errstr = NULL; - } else { - err = nsldapi_parse_result( ld, lr->lr_res_msgtype, ber, - &origerr, &matcheddn, &errstr, &v3refs, NULL ); - } - - if ( err != LDAP_SUCCESS ) { - /* parse failed */ - return; - } - - if ( origerr == LDAP_REFERRAL ) { /* ldapv3 */ - if ( v3refs != NULL ) { - err = nsldapi_chase_v3_refs( ld, lr, v3refs, - ( lr->lr_res_msgtype == LDAP_RES_SEARCH_REFERENCE ), - totalcountp, chasingcountp ); - ldap_value_free( v3refs ); - } - } else if ( ldapversion == LDAP_VERSION2 - && origerr != LDAP_SUCCESS ) { - /* referrals may be present in the error string */ - err = nsldapi_chase_v2_referrals( ld, lr, &errstr, - totalcountp, chasingcountp ); - } - - /* set LDAP errno, message, and matched string appropriately */ - if ( lr->lr_res_error != NULL ) { - NSLDAPI_FREE( lr->lr_res_error ); - } - lr->lr_res_error = errstr; - - if ( lr->lr_res_matched != NULL ) { - NSLDAPI_FREE( lr->lr_res_matched ); - } - lr->lr_res_matched = matcheddn; - - if ( err == LDAP_SUCCESS && ( *chasingcountp == *totalcountp )) { - if ( *totalcountp > 0 && ( origerr == LDAP_PARTIAL_RESULTS - || origerr == LDAP_REFERRAL )) { - /* substitute success for referral error codes */ - lr->lr_res_errno = LDAP_SUCCESS; - } else { - /* preserve existing non-referral error code */ - lr->lr_res_errno = origerr; - } - } else if ( err != LDAP_SUCCESS ) { - /* error occurred while trying to chase referrals */ - lr->lr_res_errno = err; - } else { - /* some referrals were not recognized */ - lr->lr_res_errno = ( ldapversion == LDAP_VERSION2 ) - ? LDAP_PARTIAL_RESULTS : LDAP_REFERRAL; - } - - LDAPDebug( LDAP_DEBUG_TRACE, - "check_for_refs: new result: msgid %d, res_errno %d, ", - lr->lr_msgid, lr->lr_res_errno, 0 ); - LDAPDebug( LDAP_DEBUG_TRACE, " res_error <%s>, res_matched <%s>\n", - lr->lr_res_error ? lr->lr_res_error : "", - lr->lr_res_matched ? lr->lr_res_matched : "", 0 ); - LDAPDebug( LDAP_DEBUG_TRACE, - "check_for_refs: %d new refs(s); chasing %d of them\n", - *totalcountp, *chasingcountp, 0 ); -} - - -/* returns an LDAP error code and also sets it in LDAP * */ -static int -build_result_ber( LDAP *ld, BerElement **berp, LDAPRequest *lr ) -{ - ber_len_t len; - ber_int_t along; - BerElement *ber; - int err; - - if (( err = nsldapi_alloc_ber_with_options( ld, &ber )) - != LDAP_SUCCESS ) { - return( err ); - } - *berp = ber; - if ( ber_printf( ber, lr->lr_res_ctrls ? "{it{ess}" : "{it{ess}}", - lr->lr_msgid, (long)lr->lr_res_msgtype, lr->lr_res_errno, - lr->lr_res_matched ? lr->lr_res_matched : "", - lr->lr_res_error ? lr->lr_res_error : "" ) == -1 ) { - return( LDAP_ENCODING_ERROR ); - } - - if ( NULL != lr->lr_res_ctrls && nsldapi_put_controls( ld, - lr->lr_res_ctrls, 1 /* close seq */, ber ) != LDAP_SUCCESS ) { - return( LDAP_ENCODING_ERROR ); - } - - ber_reset( ber, 1 ); - if ( ber_skip_tag( ber, &len ) == LBER_ERROR || - ber_get_int( ber, &along ) == LBER_ERROR || - ber_peek_tag( ber, &len ) == LBER_ERROR ) { - return( LDAP_DECODING_ERROR ); - } - - return( LDAP_SUCCESS ); -} - - -static void -merge_error_info( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr ) -{ -/* - * Merge error information in "lr" with "parentr" error code and string. - */ - if ( lr->lr_res_errno == LDAP_PARTIAL_RESULTS ) { - parentr->lr_res_errno = lr->lr_res_errno; - if ( lr->lr_res_error != NULL ) { - (void)nsldapi_append_referral( ld, &parentr->lr_res_error, - lr->lr_res_error ); - } - } else if ( lr->lr_res_errno != LDAP_SUCCESS && - parentr->lr_res_errno == LDAP_SUCCESS ) { - parentr->lr_res_errno = lr->lr_res_errno; - if ( parentr->lr_res_error != NULL ) { - NSLDAPI_FREE( parentr->lr_res_error ); - } - parentr->lr_res_error = lr->lr_res_error; - lr->lr_res_error = NULL; - if ( NAME_ERROR( lr->lr_res_errno )) { - if ( parentr->lr_res_matched != NULL ) { - NSLDAPI_FREE( parentr->lr_res_matched ); - } - parentr->lr_res_matched = lr->lr_res_matched; - lr->lr_res_matched = NULL; - } - } - - LDAPDebug( LDAP_DEBUG_TRACE, "merged parent (id %d) error info: ", - parentr->lr_msgid, 0, 0 ); - LDAPDebug( LDAP_DEBUG_TRACE, "result lderrno %d, error <%s>, matched <%s>\n", - parentr->lr_res_errno, parentr->lr_res_error ? - parentr->lr_res_error : "", parentr->lr_res_matched ? - parentr->lr_res_matched : "" ); -} - -#if defined( CLDAP ) -#if !defined( macintosh ) && !defined( DOS ) && !defined( _WINDOWS ) && !defined(XP_OS2) -/* XXXmcs: was revised to support extended I/O callbacks but never compiled! */ -static int -cldap_select1( LDAP *ld, struct timeval *timeout ) -{ - int rc; - static int tblsize = 0; - NSLDAPIIOStatus *iosp = ld->ld_iostatus; - - if ( tblsize == 0 ) { -#ifdef USE_SYSCONF - tblsize = sysconf( _SC_OPEN_MAX ); -#else /* USE_SYSCONF */ - tblsize = getdtablesize(); -#endif /* USE_SYSCONF */ - } - - if ( tblsize >= FD_SETSIZE ) { - /* - * clamp value so we don't overrun the fd_set structure - */ - tblsize = FD_SETSIZE - 1; - } - - if ( NSLDAPI_IOSTATUS_TYPE_OSNATIVE == iosp->ios_type ) { - fd_set readfds; - - FD_ZERO( &readfds ); - FD_SET( ld->ld_sbp->sb_sd, &readfds ); - - /* XXXmcs: UNIX platforms should use poll() */ - rc = select( tblsize, &readfds, 0, 0, timeout ) ); - - } else if ( NSLDAPI_IOSTATUS_TYPE_CALLBACK == iosp->ios_type ) { - LDAP_X_PollFD pollfds[ 1 ]; - - pollfds[0].lpoll_fd = ld->ld_sbp->sb_sd; - pollfds[0].lpoll_arg = ld->ld_sbp->sb_arg; - pollfds[0].lpoll_events = LDAP_X_POLLIN; - pollfds[0].lpoll_revents = 0; - rc = ld->ld_extpoll_fn( pollfds, 1, nsldapi_tv2ms( timeout ), - ld->ld_ext_session_arg ); - } else { - LDAPDebug( LDAP_DEBUG_ANY, - "nsldapi_iostatus_poll: unknown I/O type %d\n", - rc = 0; /* simulate a timeout (what else to do?) */ - } - - return( rc ); -} -#endif /* !macintosh */ - - -#ifdef macintosh -static int -cldap_select1( LDAP *ld, struct timeval *timeout ) -{ - /* XXXmcs: needs to be revised to support I/O callbacks */ - return( tcpselect( ld->ld_sbp->sb_sd, timeout )); -} -#endif /* macintosh */ - - -#if (defined( DOS ) && defined( WINSOCK )) || defined( _WINDOWS ) || defined(XP_OS2) -/* XXXmcs: needs to be revised to support extended I/O callbacks */ -static int -cldap_select1( LDAP *ld, struct timeval *timeout ) -{ - fd_set readfds; - int rc; - - FD_ZERO( &readfds ); - FD_SET( ld->ld_sbp->sb_sd, &readfds ); - - if ( NSLDAPI_IO_TYPE_STANDARD == ld->ldiou_type && - NULL != ld->ld_select_fn ) { - rc = ld->ld_select_fn( 1, &readfds, 0, 0, timeout ); - } else if ( NSLDAPI_IO_TYPE_EXTENDED == ld->ldiou_type && - NULL != ld->ld_extselect_fn ) { - rc = ld->ld_extselect_fn( ld->ld_ext_session_arg, 1, &readfds, 0, - 0, timeout ) ); - } else { - /* XXXmcs: UNIX platforms should use poll() */ - rc = select( 1, &readfds, 0, 0, timeout ) ); - } - - return( rc == SOCKET_ERROR ? -1 : rc ); -} -#endif /* WINSOCK || _WINDOWS */ -#endif /* CLDAP */ - -int -LDAP_CALL -ldap_msgfree( LDAPMessage *lm ) -{ - LDAPMessage *next; - int type = 0; - - LDAPDebug( LDAP_DEBUG_TRACE, "ldap_msgfree\n", 0, 0, 0 ); - - for ( ; lm != NULL; lm = next ) { - next = lm->lm_chain; - type = lm->lm_msgtype; - ber_free( lm->lm_ber, 1 ); - NSLDAPI_FREE( (char *) lm ); - } - - return( type ); -} - -/* - * ldap_msgdelete - delete a message. It returns: - * 0 if the entire message was deleted - * -1 if the message was not found, or only part of it was found - */ -int -ldap_msgdelete( LDAP *ld, int msgid ) -{ - LDAPMessage *lm, *prev; - int msgtype; - - LDAPDebug( LDAP_DEBUG_TRACE, "ldap_msgdelete\n", 0, 0, 0 ); - - if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) { - return( -1 ); /* punt */ - } - - prev = NULL; - LDAP_MUTEX_LOCK( ld, LDAP_RESP_LOCK ); - for ( lm = ld->ld_responses; lm != NULL; lm = lm->lm_next ) { - if ( lm->lm_msgid == msgid ) - break; - prev = lm; - } - - if ( lm == NULL ) - { - LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK ); - return( -1 ); - } - - if ( prev == NULL ) - ld->ld_responses = lm->lm_next; - else - prev->lm_next = lm->lm_next; - LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK ); - - msgtype = ldap_msgfree( lm ); - if ( msgtype == LDAP_RES_SEARCH_ENTRY - || msgtype == LDAP_RES_SEARCH_REFERENCE ) { - return( -1 ); - } - - return( 0 ); -} - - -/* - * return 1 if message msgid is waiting to be abandoned, 0 otherwise - */ -static int -ldap_abandoned( LDAP *ld, int msgid ) -{ - int i; - - LDAP_MUTEX_LOCK( ld, LDAP_ABANDON_LOCK ); - if ( ld->ld_abandoned == NULL ) - { - LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK ); - return( 0 ); - } - - for ( i = 0; ld->ld_abandoned[i] != -1; i++ ) - if ( ld->ld_abandoned[i] == msgid ) - { - LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK ); - return( 1 ); - } - - LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK ); - return( 0 ); -} - - -static int -ldap_mark_abandoned( LDAP *ld, int msgid ) -{ - int i; - - LDAP_MUTEX_LOCK( ld, LDAP_ABANDON_LOCK ); - if ( ld->ld_abandoned == NULL ) - { - LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK ); - return( -1 ); - } - - for ( i = 0; ld->ld_abandoned[i] != -1; i++ ) - if ( ld->ld_abandoned[i] == msgid ) - break; - - if ( ld->ld_abandoned[i] == -1 ) - { - LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK ); - return( -1 ); - } - - for ( ; ld->ld_abandoned[i] != -1; i++ ) { - ld->ld_abandoned[i] = ld->ld_abandoned[i + 1]; - } - - LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK ); - return( 0 ); -} - - -#ifdef CLDAP -int -cldap_getmsg( LDAP *ld, struct timeval *timeout, BerElement **ber ) -{ - int rc; - ber_tag_t tag; - ber_len_t len; - - if ( ld->ld_sbp->sb_ber.ber_ptr >= ld->ld_sbp->sb_ber.ber_end ) { - rc = cldap_select1( ld, timeout ); - if ( rc == -1 || rc == 0 ) { - LDAP_SET_LDERRNO( ld, (rc == -1 ? LDAP_SERVER_DOWN : - LDAP_TIMEOUT), NULL, NULL ); - return( rc ); - } - } - - /* get the next message */ - if ( (tag = ber_get_next( ld->ld_sbp, &len, ber )) - != LDAP_TAG_MESSAGE ) { - LDAP_SET_LDERRNO( ld, (tag == LBER_DEFAULT ? LDAP_SERVER_DOWN : - LDAP_LOCAL_ERROR), NULL, NULL ); - return( -1 ); - } - - return( tag ); -} -#endif /* CLDAP */ - -int -nsldapi_post_result( LDAP *ld, int msgid, LDAPMessage *result ) -{ - LDAPPend *lp; - - LDAPDebug( LDAP_DEBUG_TRACE, - "nsldapi_post_result(ld=0x%p, msgid=%d, result=0x%p)\n", - ld, msgid, result ); - LDAP_MUTEX_LOCK( ld, LDAP_PEND_LOCK ); - if( msgid == LDAP_RES_ANY ) { - /* - * Look for any pending request for which someone is waiting. - */ - for( lp = ld->ld_pend; lp != NULL; lp = lp->lp_next ) - { - if ( lp->lp_sema != NULL ) { - break; - } - } - /* - * If we did't find a pending request, lp is NULL at this - * point, and we will leave this function without doing - * anything more -- which is exactly what we want to do. - */ - } - else - { - /* - * Look for a pending request specific to this message id - */ - for( lp = ld->ld_pend; lp != NULL; lp = lp->lp_next ) - { - if( lp->lp_msgid == msgid ) - break; - } - - if( lp == NULL ) - { - /* - * No pending requests for this response... append to - * our pending result list. - */ - LDAPPend *newlp; - newlp = (LDAPPend *)NSLDAPI_CALLOC( 1, - sizeof( LDAPPend )); - if( newlp == NULL ) - { - LDAP_MUTEX_UNLOCK( ld, LDAP_PEND_LOCK ); - LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, - NULL ); - return (-1); - } - newlp->lp_msgid = msgid; - newlp->lp_result = result; - link_pend( ld, newlp ); - } - } - - - if( lp != NULL ) - { - /* - * Wake up a thread that is waiting for this result. - */ - lp->lp_msgid = msgid; - lp->lp_result = result; - LDAP_SEMA_POST( ld, lp ); - } - - LDAP_MUTEX_UNLOCK( ld, LDAP_PEND_LOCK ); - return (0); -} - -static void -link_pend( LDAP *ld, LDAPPend *lp ) -{ - if (( lp->lp_next = ld->ld_pend ) != NULL ) - { - lp->lp_next->lp_prev = lp; - } - ld->ld_pend = lp; - lp->lp_prev = NULL; -} |