/*
* Copyright 2001-2003 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/*
* 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"
#ifdef _SOLARIS_SDK
/* high resolution timer usage */
#endif
LDAPMessage **result );
#if defined( CLDAP )
#endif
#if 0 /* these functions are no longer used */
#endif /* 0 */
/*
* 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
int msgid,
int all,
)
{
int rc;
if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
return( -1 ); /* punt */
}
return( rc );
}
int
{
int rc;
/*
* 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.
*/
return( -1 );
}
} else {
result );
}
/*
* XXXmcs should use cache function pointers to hook in memcache
*/
!((*result)->lm_fromcache )) {
}
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
LDAPMessage **result )
{
} else {
}
ldap_msgfree( lm );
continue;
}
if ( all == 0
break;
break;
}
"<= check_response_queue NOT FOUND\n",
0, 0, 0 );
return( 0 ); /* no message to return */
}
break;
}
}
/*
* 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.
*/
"<= check_response_queue NOT FOUND\n",
0, 0, 0 );
return( 0 ); /* no message to return */
}
if ( all == 0 ) {
} else {
}
} else {
} else {
}
}
} else {
} else {
}
}
if ( all == 0 ) {
}
"<= check_response_queue returning msgid %d type %d\n",
return( 1 ); /* a message was found and returned in *result */
}
static int
{
int rc;
#ifdef _SOLARIS_SDK
#else
#endif
#ifdef LDAP_DEBUG
0, 0, 0 );
} else {
}
#endif /* LDAP_DEBUG */
/* check the cache */
/* if ( unlock_permitted ) LDAP_MUTEX_UNLOCK( ld ); */
/* if ( unlock_permitted ) LDAP_MUTEX_LOCK( ld ); */
if ( rc != 0 ) {
return( rc );
}
return( 0 ); /* 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.
*/
== NULL ) {
"unknown message id") ));
return( -1 ); /* could not find request for msgid */
}
return( -1 ); /* connection dead */
}
}
} else {
#ifdef _SOLARIS_SDK
start_time = gethrtime();
#else
#endif
}
rc = -2;
while ( rc == -2 ) {
#ifdef LDAP_DEBUG
if ( ldap_debug & LDAP_DEBUG_TRACE ) {
}
#endif /* LDAP_DEBUG */
break;
}
}
if ( rc == -1 ) {
"nsldapi_iostatus_poll returned -1: errno %d\n",
LDAP_GET_ERRNO( ld ), 0, 0 );
}
#endif
LDAP_BITOPT_RESTART ) == 0 ||
#else
#endif
NULL );
if ( rc == -1 ) {
NULL );
}
return( rc );
}
if ( rc == -1 ) {
} else {
rc = -2;
if ( lc->lconn_status ==
}
if ( lr
if ( rc == 0 ) {
rc = LDAP_RES_BIND;
}
else if ( rc == -1 ) {
0, 0 );
}
}
}
}
}
}
/*
* 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 == -2 &&
}
/*
* honor the timeout if specified
*/
#ifdef _SOLARIS_SDK
#else
#endif
rc = 0; /* timed out */
NULL );
break;
}
#ifdef _SOLARIS_SDK
#endif
}
}
return( rc );
}
/*
* read1msg() should be called with LDAP_CONN_LOCK and LDAP_REQ_LOCK locked.
*/
static int
LDAPMessage **result )
{
int manufactured_result = 0;
/*
* if we are not already in the midst of reading a message, allocate
* a ber that is associated with this connection
*/
return( -1 );
}
/*
* 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 */
!= LDAP_TAG_MESSAGE ) {
return( -2 ); /* try again */
}
if ( tag == LBER_DEFAULT ) {
}
return( -1 );
}
/*
* Since we have received a complete message now, we pull this ber
* out of the connection structure and never read into it again.
*/
/* message id */
return( -1 );
}
/* if it's been abandoned, toss it */
return( -2 ); /* continue looking */
}
if ( id == LDAP_RES_UNSOLICITED ) {
"no request for response with msgid %ld (tossing)\n",
id, 0, 0 );
return( -2 ); /* continue looking */
}
/* the message type */
return( -1 );
}
}
tag != LDAP_RES_SEARCH_ENTRY )) {
&refchasing );
/*
* we're chasing one or more new refs...
*/
} else if ( tag != LDAP_RES_SEARCH_REFERENCE ) {
/*
* this request is complete...
*/
/* 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_SUCCESS == lderr ) {
} else {
}
}
/*
* if this response is to a child request, we toss
* the message contents and just merge error info.
* into the parent.
*/
if ( has_parent ) {
}
if ( --lr->lr_outrefcnt > 0 ) {
break; /* not completely done yet */
}
}
/*
* we recognize a request as complete when:
* 1) it has no outstanding referrals
* 2) it is not a child request
* 3) we have received a result for the request (i.e.,
* something other than an entry or a reference).
*/
"request %ld done\n", id, 0, 0 );
"res_errno: %d, res_error: <%s>, res_matched: <%s>\n",
if ( !simple_request ) {
}
!= LDAP_SUCCESS ) {
} else {
manufactured_result = 1;
}
}
} else {
}
}
}
return( rc );
}
/* make a new ldap message */
== NULL ) {
return( -1 );
}
/*
* 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 ) {
}
/*
* return the first response we have for this
* search request later (possibly an entire
* chain of messages).
*/
foundit = 1;
} else if ( all == 0
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.
*/
break;
prev = l;
}
/* not part of an existing search response */
if ( l == NULL ) {
if ( foundit ) {
return( tag );
}
"adding new response id %d type %d (looking for id %d)\n",
if( message_can_be_returned )
return( -2 ); /* continue looking */
}
"adding response id %d type %d (looking for id %d)\n",
/*
* 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.
*/
}
/*
* 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 &&
/*
* the result is the only thing in the chain... replace it.
*/
} else {
}
} else {
}
if ( l == tmp ) {
l = new;
}
ldap_msgfree( tmp );
/*
* entries or references are also present, so the result
* is the next entry after tmp. replace it.
*/
/*
* the result is the only thing in the chain... add before it.
*/
} else {
}
} else {
}
if ( l == tmp ) {
l = new;
}
} else {
/*
*/
}
/*
* return the first response or the whole chain if that's what
* we were looking for....
*/
if ( foundit ) {
/*
* only return the first response in the chain
*/
} else {
}
tag = l->lm_msgtype;
} else {
/*
* return all of the responses (may be a chain)
*/
} else {
}
}
*result = l;
return( tag );
}
return( -2 ); /* continue looking */
}
/*
* check for LDAPv2+ (UMich extension) or LDAPv3 referrals or references
* errors are merged in "lr".
*/
static void
{
*chasingcountp = *totalcountp = 0;
/* referrals are not supported or are disabled */
return;
}
} else {
}
if ( err != LDAP_SUCCESS ) {
/* parse failed */
return;
}
}
} else if ( ldapversion == LDAP_VERSION2
&& origerr != LDAP_SUCCESS ) {
/* referrals may be present in the error string */
}
/* set LDAP errno, message, and matched string appropriately */
}
}
|| origerr == LDAP_REFERRAL )) {
/* substitute success for referral error codes */
} else {
/* preserve existing non-referral error code */
}
} else if ( err != LDAP_SUCCESS ) {
/* error occurred while trying to chase referrals */
} else {
/* some referrals were not recognized */
}
"check_for_refs: new result: msgid %d, res_errno %d, ",
"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
{
int err;
!= LDAP_SUCCESS ) {
return( err );
}
return( LDAP_ENCODING_ERROR );
}
return( LDAP_DECODING_ERROR );
}
return( LDAP_SUCCESS );
}
static void
{
/*
* Merge error information in "lr" with "parentr" error code and string.
*/
lr->lr_res_error );
}
}
}
}
}
}
#if defined( CLDAP )
/* XXXmcs: was revised to support extended I/O callbacks but never compiled! */
static int
{
int rc;
static int tblsize = 0;
if ( tblsize == 0 ) {
#ifdef USE_SYSCONF
#else /* USE_SYSCONF */
tblsize = getdtablesize();
#endif /* USE_SYSCONF */
}
if ( tblsize >= FD_SETSIZE ) {
/*
* clamp value so we don't overrun the fd_set structure
*/
}
/* XXXmcs: UNIX platforms should use poll() */
pollfds[0].lpoll_revents = 0;
ld->ld_ext_session_arg );
} else {
"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
{
/* XXXmcs: needs to be revised to support I/O callbacks */
}
#endif /* macintosh */
/* XXXmcs: needs to be revised to support extended I/O callbacks */
static int
{
int rc;
0, timeout ) );
} else {
/* XXXmcs: UNIX platforms should use poll() */
}
}
#endif /* WINSOCK || _WINDOWS */
#endif /* CLDAP */
int
{
int type = 0;
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
{
int msgtype;
if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
return( -1 ); /* punt */
}
break;
}
{
return( -1 );
}
else
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
{
int i;
{
return( 0 );
}
{
return( 1 );
}
return( 0 );
}
static int
{
int i;
{
return( -1 );
}
break;
{
return( -1 );
}
}
return( 0 );
}
#ifdef CLDAP
int
{
int rc;
return( rc );
}
}
/* get the next message */
!= LDAP_TAG_MESSAGE ) {
return( -1 );
}
return( tag );
}
#endif /* CLDAP */
int
{
"nsldapi_post_result(ld=0x%x, msgid=%d, result=0x%x)\n",
if( msgid == LDAP_RES_ANY ) {
/*
* Look for any pending request for which someone is waiting.
*/
{
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
*/
{
break;
}
{
/*
* No pending requests for this response... append to
* our pending result list.
*/
sizeof( LDAPPend ));
{
NULL );
return (-1);
}
}
}
{
/*
* Wake up a thread that is waiting for this result.
*/
}
return (0);
}
static void
{
{
}
}
#if 0 /* these functions are no longer used */
static void
{
} else {
}
}
}
static int
{
int rc;
{
{
if ( all == 0
break;
break;
}
break;
}
}
{
if ( all == 0 )
{
{
else
}
else
{
{
}
else
{
}
}
}
else
{
else
}
if ( all == 0 )
}
else
{
rc = -2;
}
return ( rc );
}
#endif /* 0 */