Diff for /libraries/libldap/result.c between versions 1.26 and 1.124.2.21

version 1.26, 1999/05/28 03:19:18 version 1.124.2.21, 2010/04/13 20:22:59
Line 1 Line 1
 /*  /* result.c - wait for an ldap result */
  * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.  /* $OpenLDAP: pkg/ldap/libraries/libldap/result.c,v 1.124.2.20 2009/11/18 17:04:31 quanah Exp $ */
  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file  /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
    *
    * Copyright 1998-2010 The OpenLDAP Foundation.
    * All rights reserved.
    *
    * Redistribution and use in source and binary forms, with or without
    * modification, are permitted only as authorized by the OpenLDAP
    * Public License.
    *
    * A copy of this license is available in the file LICENSE in the
    * top-level directory of the distribution or, alternatively, at
    * <http://www.OpenLDAP.org/license.html>.
    */
   /* Portions Copyright (c) 1990 Regents of the University of Michigan.
    * All rights reserved.
  */   */
 /*  Portions  /* This notice applies to changes, created by or for Novell, Inc.,
  *  Copyright (c) 1990 Regents of the University of Michigan.   * to preexisting works for which notices appear elsewhere in this file.
  *  All rights reserved.  
  *   *
  *  result.c - wait for an ldap result   * Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved.
    *
    * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND TREATIES.
    * USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO VERSION
    * 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS AVAILABLE AT
    * HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE" IN THE
    * TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION OF THIS
    * WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP PUBLIC
    * LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT THE
    * PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY. 
    *---
    * Modification to OpenLDAP source by Novell, Inc.
    * April 2000 sfs Add code to process V3 referrals and search results
    *---
    * Note: A verbatim copy of version 2.0.1 of the OpenLDAP Public License 
    * can be found in the file "build/LICENSE-2.0.1" in this distribution
    * of OpenLDAP Software.
    */
   
   /*
    * LDAPv3 (RFC 4511)
    *      LDAPResult ::= SEQUENCE {
    *              resultCode                      ENUMERATED { ... },
    *              matchedDN                       LDAPDN,
    *              diagnosticMessage               LDAPString,
    *              referral                        [3] Referral OPTIONAL
    *      }
    *      Referral ::= SEQUENCE OF LDAPURL        (one or more)
    *      LDAPURL ::= LDAPString                  (limited to URL chars)
  */   */
   
 #include "portable.h"  #include "portable.h"
   
 #include <stdio.h>  #include <stdio.h>
 #include <stdlib.h>  
   #include <ac/stdlib.h>
   
 #include <ac/errno.h>  #include <ac/errno.h>
 #include <ac/socket.h>  #include <ac/socket.h>
Line 21 Line 63
 #include <ac/unistd.h>  #include <ac/unistd.h>
   
 #include "ldap-int.h"  #include "ldap-int.h"
   #include "ldap_log.h"
   #include "lutil.h"
   
   static int ldap_abandoned LDAP_P(( LDAP *ld, ber_int_t msgid, int *idx ));
 static int ldap_abandoned LDAP_P(( LDAP *ld, int msgid ));  static int ldap_mark_abandoned LDAP_P(( LDAP *ld, ber_int_t msgid, int idx ));
 static int ldap_mark_abandoned LDAP_P(( LDAP *ld, int msgid ));  static int wait4msg LDAP_P(( LDAP *ld, ber_int_t msgid, int all, struct timeval *timeout,
 static int wait4msg LDAP_P(( LDAP *ld, int msgid, int all, struct timeval *timeout,  
         LDAPMessage **result ));  
 static int try_read1msg LDAP_P(( LDAP *ld, int msgid, int all, Sockbuf *sb, LDAPConn *lc,  
         LDAPMessage **result ));          LDAPMessage **result ));
 static unsigned long build_result_ber LDAP_P(( LDAP *ld, BerElement *ber, LDAPRequest *lr ));  static ber_tag_t try_read1msg LDAP_P(( LDAP *ld, ber_int_t msgid,
           int all, LDAPConn *lc, LDAPMessage **result ));
   static ber_tag_t build_result_ber LDAP_P(( LDAP *ld, BerElement **bp, LDAPRequest *lr ));
 static void merge_error_info LDAP_P(( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr ));  static void merge_error_info LDAP_P(( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr ));
   static LDAPMessage * chkResponseList LDAP_P(( LDAP *ld, int msgid, int all));
   
   #define LDAP_MSG_X_KEEP_LOOKING         (-2)
   
   
 /*  /*
  * ldap_result - wait for an ldap result response to a message from the   * 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 server.  If msgid is LDAP_RES_ANY (-1), any message will be
  * ldap_result will wait for a response with msgid.  If all is 0 the   * accepted.  If msgid is LDAP_RES_UNSOLICITED (0), any unsolicited
  * first message with id msgid will be accepted, otherwise, ldap_result   * message is accepted.  Otherwise ldap_result will wait for a response
  * will wait for all responses with id msgid and then return a pointer to   * with msgid.  If all is LDAP_MSG_ONE (0) the first message with id
  * the entire list of messages.  This is only useful for search responses,   * msgid will be accepted, otherwise, ldap_result will wait for all
  * which can be of two message types (zero or more entries, followed by an   * responses with id msgid and then return a pointer to the entire list
  * ldap result).  The type of the first message received is returned.   * of messages.  In general, this is only useful for search responses,
  * When waiting, any messages that have been abandoned are discarded.   * which can be of three message types (zero or more entries, zero or
    * search references, followed by an ldap result).  An extension to
    * LDAPv3 allows partial extended responses to be returned in response
    * to any request.  The type of the first message received is returned.
    * When waiting, any messages that have been abandoned/discarded are 
    * discarded.
  *   *
  * Example:   * Example:
  *      ldap_result( s, msgid, all, timeout, result )   *      ldap_result( s, msgid, all, timeout, result )
  */   */
 int  int
 ldap_result( LDAP *ld, int msgid, int all, struct timeval *timeout,  ldap_result(
           LDAP *ld,
           int msgid,
           int all,
           struct timeval *timeout,
         LDAPMessage **result )          LDAPMessage **result )
 {  {
         LDAPMessage     *lm, *lastlm, *nextlm;          int             rc;
   
         assert( ld != NULL );          assert( ld != NULL );
         assert( result != NULL );          assert( result != NULL );
   
         Debug( LDAP_DEBUG_TRACE, "ldap_result\n", 0, 0, 0 );          Debug( LDAP_DEBUG_TRACE, "ldap_result ld %p msgid %d\n", (void *)ld, msgid, 0 );
   
         if( ld == NULL ) {  #ifdef LDAP_R_COMPILE
                 return -1;          ldap_pvt_thread_mutex_lock( &ld->ld_res_mutex );
         }  #endif
   
         if( result == NULL ) {          rc = wait4msg( ld, msgid, all, timeout, result );
                 ld->ld_errno = LDAP_PARAM_ERROR;  
                 return -1;  #ifdef LDAP_R_COMPILE
         }          ldap_pvt_thread_mutex_unlock( &ld->ld_res_mutex );
   #endif
   
           return rc;
   }
   
   static LDAPMessage *
   chkResponseList(
           LDAP *ld,
           int msgid,
           int all)
   {
           LDAPMessage     *lm, **lastlm, *nextlm;
           int             cnt = 0;
   
         /*          /*
          * First, look through the list of responses we have received on           * Look through the list of responses we have received on
          * this association and see if the response we're interested in           * this association and see if the response we're interested in
          * is there.  If it is, return it.  If not, call wait4msg() to           * is there.  If it is, return it.  If not, call wait4msg() to
          * wait until it arrives or timeout occurs.           * wait until it arrives or timeout occurs.
          */           */
   
         *result = NULLMSG;  #ifdef LDAP_R_COMPILE
         lastlm = NULLMSG;          LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex );
         for ( lm = ld->ld_responses; lm != NULLMSG; lm = nextlm ) {  #endif
   
           Debug( LDAP_DEBUG_TRACE,
                   "ldap_chkResponseList ld %p msgid %d all %d\n",
                   (void *)ld, msgid, all );
   
           lastlm = &ld->ld_responses;
           for ( lm = ld->ld_responses; lm != NULL; lm = nextlm ) {
                   int     idx;
   
                 nextlm = lm->lm_next;                  nextlm = lm->lm_next;
                   ++cnt;
   
                 if ( ldap_abandoned( ld, lm->lm_msgid ) ) {                  if ( ldap_abandoned( ld, lm->lm_msgid, &idx ) ) {
                         ldap_mark_abandoned( ld, lm->lm_msgid );                          Debug( LDAP_DEBUG_ANY,
                                   "response list msg abandoned, "
                                   "msgid %d message type %s\n",
                                   lm->lm_msgid, ldap_int_msgtype2str( lm->lm_msgtype ), 0 );
   
                           switch ( lm->lm_msgtype ) {
                           case LDAP_RES_SEARCH_ENTRY:
                           case LDAP_RES_SEARCH_REFERENCE:
                           case LDAP_RES_INTERMEDIATE:
                                   break;
   
                         if ( lastlm == NULLMSG ) {                          default:
                                 ld->ld_responses = lm->lm_next;                                  /* there's no need to keep the id
                         } else {                                   * in the abandoned list any longer */
                                 lastlm->lm_next = nextlm;                                  ldap_mark_abandoned( ld, lm->lm_msgid, idx );
                                   break;
                         }                          }
   
                           /* Remove this entry from list */
                           *lastlm = nextlm;
   
                         ldap_msgfree( lm );                          ldap_msgfree( lm );
   
                         continue;                          continue;
Line 96  ldap_result( LDAP *ld, int msgid, int al Line 187  ldap_result( LDAP *ld, int msgid, int al
                 if ( msgid == LDAP_RES_ANY || lm->lm_msgid == msgid ) {                  if ( msgid == LDAP_RES_ANY || lm->lm_msgid == msgid ) {
                         LDAPMessage     *tmp;                          LDAPMessage     *tmp;
   
                         if ( all == 0                          if ( all == LDAP_MSG_ONE ||
                             || (lm->lm_msgtype != LDAP_RES_SEARCH_RESULT                                  all == LDAP_MSG_RECEIVED ||
                             && lm->lm_msgtype != LDAP_RES_SEARCH_REFERENCE      /* LDAPv3 */                                  msgid == LDAP_RES_UNSOLICITED )
                             && lm->lm_msgtype != LDAP_RES_SEARCH_ENTRY) )                          {
                                 break;                                  break;
                           }
   
                         for ( tmp = lm; tmp != NULLMSG; tmp = tmp->lm_chain ) {                          tmp = lm->lm_chain_tail;
                                 if ( tmp->lm_msgtype == LDAP_RES_SEARCH_RESULT )                          if ( tmp->lm_msgtype == LDAP_RES_SEARCH_ENTRY ||
                                         break;                                  tmp->lm_msgtype == LDAP_RES_SEARCH_REFERENCE ||
                                   tmp->lm_msgtype == LDAP_RES_INTERMEDIATE )
                           {
                                   tmp = NULL;
                         }                          }
   
                         if ( tmp == NULLMSG ) {                          if ( tmp == NULL ) {
                                 return( wait4msg( ld, msgid, all, timeout,                                  lm = NULL;
                                     result ) );  
                         }                          }
   
                         break;                          break;
                 }                  }
                 lastlm = lm;                  lastlm = &lm->lm_next;
         }          }
         if ( lm == NULLMSG ) {  
                 return( wait4msg( ld, msgid, all, timeout, result ) );          if ( lm != NULL ) {
                   /* Found an entry, remove it from the list */
                   if ( all == LDAP_MSG_ONE && lm->lm_chain != NULL ) {
                           *lastlm = lm->lm_chain;
                           lm->lm_chain->lm_next = lm->lm_next;
                           lm->lm_chain->lm_chain_tail = ( lm->lm_chain_tail != lm ) ? lm->lm_chain_tail : lm->lm_chain;
                           lm->lm_chain = NULL;
                           lm->lm_chain_tail = NULL;
                   } else {
                           *lastlm = lm->lm_next;
                   }
                   lm->lm_next = NULL;
         }          }
   
         if ( lastlm == NULLMSG ) {  #ifdef LDAP_DEBUG
                 ld->ld_responses = (all == 0 && lm->lm_chain != NULLMSG          if ( lm == NULL) {
                     ? lm->lm_chain : lm->lm_next);                  Debug( LDAP_DEBUG_TRACE,
                           "ldap_chkResponseList returns ld %p NULL\n", (void *)ld, 0, 0);
         } else {          } else {
                 lastlm->lm_next = (all == 0 && lm->lm_chain != NULLMSG                  Debug( LDAP_DEBUG_TRACE,
                     ? lm->lm_chain : lm->lm_next);                          "ldap_chkResponseList returns ld %p msgid %d, type 0x%02lx\n",
                           (void *)ld, lm->lm_msgid, (unsigned long)lm->lm_msgtype );
         }          }
         if ( all == 0 )  #endif
                 lm->lm_chain = NULLMSG;  
         lm->lm_next = NULLMSG;          return lm;
   
         *result = lm;  
         ld->ld_errno = LDAP_SUCCESS;  
         return( lm->lm_msgtype );  
 }  }
   
 static int  static int
 wait4msg( LDAP *ld, int msgid, int all, struct timeval *timeout,  wait4msg(
           LDAP *ld,
           ber_int_t msgid,
           int all,
           struct timeval *timeout,
         LDAPMessage **result )          LDAPMessage **result )
 {  {
         int             rc;          int             rc;
         struct timeval  tv, *tvp;          struct timeval  tv = { 0 },
         time_t          start_time = 0;                          tv0 = { 0 },
         time_t          tmp_time;                          start_time_tv = { 0 },
         LDAPConn        *lc, *nextlc;                          *tvp = NULL;
           LDAPConn        *lc;
   
         assert( ld != NULL );          assert( ld != NULL );
         assert( result != NULL );          assert( result != NULL );
   
   #ifdef LDAP_R_COMPILE
           LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex );
   #endif
   
           if ( timeout == NULL && ld->ld_options.ldo_tm_api.tv_sec >= 0 ) {
                   tv = ld->ld_options.ldo_tm_api;
                   timeout = &tv;
           }
   
 #ifdef LDAP_DEBUG  #ifdef LDAP_DEBUG
         if ( timeout == NULL ) {          if ( timeout == NULL ) {
                 Debug( LDAP_DEBUG_TRACE, "wait4msg (infinite timeout)\n",                  Debug( LDAP_DEBUG_TRACE, "wait4msg ld %p msgid %d (infinite timeout)\n",
                     0, 0, 0 );                          (void *)ld, msgid, 0 );
         } else {          } else {
                 Debug( LDAP_DEBUG_TRACE, "wait4msg (timeout %ld sec, %ld usec)\n",                  Debug( LDAP_DEBUG_TRACE, "wait4msg ld %p msgid %d (timeout %ld usec)\n",
                        (long) timeout->tv_sec, (long) timeout->tv_usec, 0 );                          (void *)ld, msgid, (long)timeout->tv_sec * 1000000 + timeout->tv_usec );
         }          }
 #endif /* LDAP_DEBUG */  #endif /* LDAP_DEBUG */
   
         if ( timeout == NULL ) {          if ( timeout != NULL && timeout->tv_sec != -1 ) {
                 tvp = NULL;                  tv0 = *timeout;
         } else {  
                 tv = *timeout;                  tv = *timeout;
                 tvp = &tv;                  tvp = &tv;
                 start_time = time( NULL );  #ifdef HAVE_GETTIMEOFDAY
                   gettimeofday( &start_time_tv, NULL );
   #else /* ! HAVE_GETTIMEOFDAY */
                   time( &start_time_tv.tv_sec );
                   start_time_tv.tv_usec = 0;
   #endif /* ! HAVE_GETTIMEOFDAY */
         }          }
                                           
         rc = -2;          rc = LDAP_MSG_X_KEEP_LOOKING;
         while ( rc == -2 ) {          while ( rc == LDAP_MSG_X_KEEP_LOOKING ) {
 #ifdef LDAP_DEBUG  #ifdef LDAP_DEBUG
                 if ( ldap_debug & LDAP_DEBUG_TRACE ) {                  if ( ldap_debug & LDAP_DEBUG_TRACE ) {
                           Debug( LDAP_DEBUG_TRACE, "wait4msg continue ld %p msgid %d all %d\n",
                                   (void *)ld, msgid, all );
   #ifdef LDAP_R_COMPILE
                           ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex );
   #endif
                         ldap_dump_connection( ld, ld->ld_conns, 1 );                          ldap_dump_connection( ld, ld->ld_conns, 1 );
   #ifdef LDAP_R_COMPILE
                           ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex );
                           ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
   #endif
                         ldap_dump_requests_and_responses( ld );                          ldap_dump_requests_and_responses( ld );
   #ifdef LDAP_R_COMPILE
                           ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
   #endif
                 }                  }
 #endif /* LDAP_DEBUG */  #endif /* LDAP_DEBUG */
                 for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {  
                         if ( ber_pvt_sb_data_ready(lc->lconn_sb) ) {  
                                 rc = try_read1msg( ld, msgid, all, lc->lconn_sb,  
                                     lc, result );  
                                 break;  
                         }  
                 }  
   
                 if ( lc == NULL ) {                  if ( ( *result = chkResponseList( ld, msgid, all ) ) != NULL ) {
                         rc = do_ldap_select( ld, tvp );                          rc = (*result)->lm_msgtype;
   
                   } else {
                           int lc_ready = 0;
   
 #ifdef LDAP_DEBUG  #ifdef LDAP_R_COMPILE
                         if ( rc == -1 ) {                          ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex );
                             Debug( LDAP_DEBUG_TRACE,  #endif
                                     "do_ldap_select returned -1: errno %d\n",                          for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {
                                     errno, 0, 0 );                                  if ( ber_sockbuf_ctrl( lc->lconn_sb,
                                           LBER_SB_OPT_DATA_READY, NULL ) )
                                   {
                                           lc_ready = 1;
                                           break;
                                   }
                         }                          }
   #ifdef LDAP_R_COMPILE
                           ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex );
 #endif  #endif
   
                         if ( rc == 0 || ( rc == -1 && (                          if ( !lc_ready ) {
                                 ( LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_RESTART)                                  int err;
                                         == LDAP_OPT_OFF )                                  rc = ldap_int_select( ld, tvp );
                                 || errno != EINTR )))                                  if ( rc == -1 ) {
                         {                                          err = sock_errno();
                                 ld->ld_errno = (rc == -1 ? LDAP_SERVER_DOWN :  #ifdef LDAP_DEBUG
                                     LDAP_TIMEOUT);                                          Debug( LDAP_DEBUG_TRACE,
                                 return( rc );                                                  "ldap_int_select returned -1: errno %d\n",
                                                   err, 0, 0 );
   #endif
                                   }
   
                                   if ( rc == 0 || ( rc == -1 && (
                                           !LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_RESTART)
                                                   || err != EINTR ) ) )
                                   {
                                           ld->ld_errno = (rc == -1 ? LDAP_SERVER_DOWN :
                                                   LDAP_TIMEOUT);
                                           return( rc );
                                   }
   
                                   if ( rc == -1 ) {
                                           rc = LDAP_MSG_X_KEEP_LOOKING;   /* select interrupted: loop */
   
                                   } else {
                                           lc_ready = 1;
                                   }
                         }                          }
                           if ( lc_ready ) {
                                   LDAPConn *lnext;
                                   rc = LDAP_MSG_X_KEEP_LOOKING;
   #ifdef LDAP_R_COMPILE
                                   ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
   #endif
                                   if ( ld->ld_requests &&
                                           ld->ld_requests->lr_status == LDAP_REQST_WRITING &&
                                           ldap_is_write_ready( ld,
                                                   ld->ld_requests->lr_conn->lconn_sb ) )
                                   {
                                           ldap_int_flush_request( ld, ld->ld_requests );
                                   }
   #ifdef LDAP_R_COMPILE
                                   ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
                                   ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex );
   #endif
                                   for ( lc = ld->ld_conns;
                                           rc == LDAP_MSG_X_KEEP_LOOKING && lc != NULL;
                                           lc = lnext )
                                   {
                                           if ( lc->lconn_status == LDAP_CONNST_CONNECTED &&
                                                   ldap_is_read_ready( ld, lc->lconn_sb ) )
                                           {
                                                   /* Don't let it get freed out from under us */
                                                   ++lc->lconn_refcnt;
   #ifdef LDAP_R_COMPILE
                                                   ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex );
   #endif
                                                   rc = try_read1msg( ld, msgid, all, lc, result );
                                                   lnext = lc->lconn_next;
   
                         if ( rc == -1 ) {                                                  /* Only take locks if we're really freeing */
                                 rc = -2;        /* select interrupted: loop */                                                  if ( lc->lconn_refcnt <= 1 ) {
                         } else {  #ifdef LDAP_R_COMPILE
                                 rc = -2;                                                          ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
                                 for ( lc = ld->ld_conns; rc == -2 && lc != NULL;  #endif
                                     lc = nextlc ) {                                                          ldap_free_connection( ld, lc, 0, 1 );
                                         nextlc = lc->lconn_next;  #ifdef LDAP_R_COMPILE
                                         if ( lc->lconn_status ==                                                          ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
                                             LDAP_CONNST_CONNECTED &&  #endif
                                             ldap_is_read_ready( ld,                                                  } else {
                                             lc->lconn_sb )) {                                                          --lc->lconn_refcnt;
                                                 rc = try_read1msg( ld, msgid, all,                                                  }
                                                     lc->lconn_sb, lc, result );  #ifdef LDAP_R_COMPILE
                                                   ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex );
   #endif
                                           } else {
                                                   lnext = lc->lconn_next;
                                         }                                          }
                                 }                                  }
   #ifdef LDAP_R_COMPILE
                                   ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex );
   #endif
                         }                          }
                 }                  }
   
                 if ( rc == -2 && tvp != NULL ) {                  if ( rc == LDAP_MSG_X_KEEP_LOOKING && tvp != NULL ) {
                         tmp_time = time( NULL );                          struct timeval  curr_time_tv = { 0 },
                         if (( tv.tv_sec -=  ( tmp_time - start_time )) <= 0 ) {                                          delta_time_tv = { 0 };
                                 rc = 0; /* timed out */  
   #ifdef HAVE_GETTIMEOFDAY
                           gettimeofday( &curr_time_tv, NULL );
   #else /* ! HAVE_GETTIMEOFDAY */
                           time( &curr_time_tv.tv_sec );
                           curr_time_tv.tv_usec = 0;
   #endif /* ! HAVE_GETTIMEOFDAY */
   
                           /* delta_time = tmp_time - start_time */
                           delta_time_tv.tv_sec = curr_time_tv.tv_sec - start_time_tv.tv_sec;
                           delta_time_tv.tv_usec = curr_time_tv.tv_usec - start_time_tv.tv_usec;
                           if ( delta_time_tv.tv_usec < 0 ) {
                                   delta_time_tv.tv_sec--;
                                   delta_time_tv.tv_usec += 1000000;
                           }
   
                           /* tv0 < delta_time ? */
                           if ( ( tv0.tv_sec < delta_time_tv.tv_sec ) ||
                                ( ( tv0.tv_sec == delta_time_tv.tv_sec ) && ( tv0.tv_usec < delta_time_tv.tv_usec ) ) )
                           {
                                   rc = 0; /* timed out */
                                 ld->ld_errno = LDAP_TIMEOUT;                                  ld->ld_errno = LDAP_TIMEOUT;
                                 break;                                  break;
                         }                          }
   
                         Debug( LDAP_DEBUG_TRACE, "wait4msg:  %ld secs to go\n",                          /* tv0 -= delta_time */
                                (long) tv.tv_sec, 0, 0 );                          tv0.tv_sec -= delta_time_tv.tv_sec;
                         start_time = tmp_time;                          tv0.tv_usec -= delta_time_tv.tv_usec;
                           if ( tv0.tv_usec < 0 ) {
                                   tv0.tv_sec--;
                                   tv0.tv_usec += 1000000;
                           }
   
                           tv.tv_sec = tv0.tv_sec;
                           tv.tv_usec = tv0.tv_usec;
   
                           Debug( LDAP_DEBUG_TRACE, "wait4msg ld %p %ld s %ld us to go\n",
                                   (void *)ld, (long) tv.tv_sec, (long) tv.tv_usec );
   
                           start_time_tv.tv_sec = curr_time_tv.tv_sec;
                           start_time_tv.tv_usec = curr_time_tv.tv_usec;
                 }                  }
         }          }
   
Line 241  wait4msg( LDAP *ld, int msgid, int all, Line 466  wait4msg( LDAP *ld, int msgid, int all,
 }  }
   
   
 static int  static ber_tag_t
 try_read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb,  try_read1msg(
     LDAPConn *lc, LDAPMessage **result )          LDAP *ld,
           ber_int_t msgid,
           int all,
           LDAPConn *lc,
           LDAPMessage **result )
 {  {
         BerElement      *ber;          BerElement      *ber;
         LDAPMessage     *new, *l, *prev, *tmp;          LDAPMessage     *newmsg, *l, *prev;
         long            id;          ber_int_t       id;
         unsigned long   tag, len;          int             idx;
           ber_tag_t       tag;
           ber_len_t       len;
         int             foundit = 0;          int             foundit = 0;
         LDAPRequest     *lr;          LDAPRequest     *lr, *tmplr, dummy_lr = { 0 };
         BerElement      tmpber;          BerElement      tmpber;
         int             rc, refer_cnt, hadref, simple_request;          int             rc, refer_cnt, hadref, simple_request, err;
         unsigned long   lderr;          ber_int_t       lderr;
   
   #ifdef LDAP_CONNECTIONLESS
           LDAPMessage     *tmp = NULL, *chain_head = NULL;
           int             moremsgs = 0, isv2 = 0;
   #endif
   
         assert( ld != NULL );          assert( ld != NULL );
         assert( lc != NULL );          assert( lc != NULL );
                   
         ber = &lc->lconn_ber;  #ifdef LDAP_R_COMPILE
           LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex );
   #endif
   
         Debug( LDAP_DEBUG_TRACE, "read1msg\n", 0, 0, 0 );          Debug( LDAP_DEBUG_TRACE, "read1msg: ld %p msgid %d all %d\n",
                   (void *)ld, msgid, all );
   
 #if 0  retry:
         ber_init_w_nullc( &ber, 0 );          if ( lc->lconn_ber == NULL ) {
         ldap_set_ber_options( ld, &ber );                  lc->lconn_ber = ldap_alloc_ber_with_options( ld );
 #endif  
                   if ( lc->lconn_ber == NULL ) {
                           return -1;
                   }
           }
   
           ber = lc->lconn_ber;
           assert( LBER_VALID (ber) );
   
         /* get the next message */          /* get the next message */
         errno = 0;          sock_errset(0);
         if ( (tag = ber_get_next( sb, &len, ber ))  #ifdef LDAP_CONNECTIONLESS
             != LDAP_TAG_MESSAGE ) {          if ( LDAP_IS_UDP(ld) ) {
                 if ( tag == LBER_DEFAULT) {                  struct sockaddr from;
                   ber_int_sb_read( lc->lconn_sb, &from, sizeof(struct sockaddr) );
                   if ( ld->ld_options.ldo_version == LDAP_VERSION2 ) isv2 = 1;
           }
   nextresp3:
   #endif
           tag = ber_get_next( lc->lconn_sb, &len, ber );
           switch ( tag ) {
           case LDAP_TAG_MESSAGE:
                   /*
                    * We read a complete message.
                    * The connection should no longer need this ber.
                    */
                   lc->lconn_ber = NULL;
                   break;
   
           case LBER_DEFAULT:
                   err = sock_errno();
 #ifdef LDAP_DEBUG                    #ifdef LDAP_DEBUG                  
                         Debug( LDAP_DEBUG_CONNS,                  Debug( LDAP_DEBUG_CONNS,
                               "ber_get_next failed.\n", 0, 0, 0 );                          "ber_get_next failed.\n", 0, 0, 0 );
 #endif               #endif             
 #ifdef EWOULDBLOCK                        #ifdef EWOULDBLOCK                      
                         if (errno==EWOULDBLOCK) return -2;                  if ( err == EWOULDBLOCK ) return LDAP_MSG_X_KEEP_LOOKING;
 #endif  #endif
 #ifdef EAGAIN  #ifdef EAGAIN
                         if (errno == EAGAIN) return -2;                  if ( err == EAGAIN ) return LDAP_MSG_X_KEEP_LOOKING;
 #endif  #endif
                         ld->ld_errno = LDAP_SERVER_DOWN;                  ld->ld_errno = LDAP_SERVER_DOWN;
                         return -1;                  --lc->lconn_refcnt;
                 }                  lc->lconn_status = 0;
                   return -1;
   
           default:
                 ld->ld_errno = LDAP_LOCAL_ERROR;                  ld->ld_errno = LDAP_LOCAL_ERROR;
                 return -1;                  return -1;
         }          }
   
         /* message id */          /* message id */
         if ( ber_get_int( ber, &id ) == LBER_ERROR ) {          if ( ber_get_int( ber, &id ) == LBER_ERROR ) {
                   ber_free( ber, 1 );
                 ld->ld_errno = LDAP_DECODING_ERROR;                  ld->ld_errno = LDAP_DECODING_ERROR;
                 return( -1 );                  return( -1 );
         }          }
   
           /* id == 0 iff unsolicited notification message (RFC 4511) */
   
           /* id < 0 is invalid, just toss it. FIXME: should we disconnect? */
           if ( id < 0 ) {
                   goto retry_ber;
           }
           
         /* if it's been abandoned, toss it */          /* if it's been abandoned, toss it */
         if ( ldap_abandoned( ld, (int)id ) ) {          if ( id > 0 ) {
                 ber_clear( ber, 1 );    /* gack! */                  if ( ldap_abandoned( ld, id, &idx ) ) {
                 return( -2 );   /* continue looking */                          /* the message type */
         }                          tag = ber_peek_tag( ber, &len );
                           switch ( tag ) {
         if (( lr = ldap_find_request_by_msgid( ld, id )) == NULL ) {                          case LDAP_RES_SEARCH_ENTRY:
                 Debug( LDAP_DEBUG_ANY,                          case LDAP_RES_SEARCH_REFERENCE:
                     "no request for response with msgid %ld (tossing)\n",                          case LDAP_RES_INTERMEDIATE:
                     id, 0, 0 );                          case LBER_ERROR:
                 ber_clear( ber, 1 );    /* gack! */                                  break;
                 return( -2 );   /* continue looking */  
         }                          default:
         Debug( LDAP_DEBUG_TRACE, "ldap_read: %s msgid %ld, original id %d\n",                                  /* there's no need to keep the id
             ( tag == LDAP_RES_SEARCH_ENTRY ) ? "entry" :                                    * in the abandoned list any longer */
                 ( tag == LDAP_RES_SEARCH_REFERENCE ) ? "reference" : "result",                                  ldap_mark_abandoned( ld, id, idx );
                 id, lr->lr_origid );                                  break;
         id = lr->lr_origid;                          }
   
                           Debug( LDAP_DEBUG_ANY,
                                   "abandoned/discarded ld %p msgid %d message type %s\n",
                                   (void *)ld, id, ldap_int_msgtype2str( tag ) );
   
   retry_ber:
                           ber_free( ber, 1 );
                           if ( ber_sockbuf_ctrl( lc->lconn_sb, LBER_SB_OPT_DATA_READY, NULL ) ) {
                                   goto retry;
                           }
                           return( LDAP_MSG_X_KEEP_LOOKING );      /* continue looking */
                   }
   
                   lr = ldap_find_request_by_msgid( ld, id );
                   if ( lr == NULL ) {
                           const char      *msg = "unknown";
   
                           /* the message type */
                           tag = ber_peek_tag( ber, &len );
                           switch ( tag ) {
                           case LBER_ERROR:
                                   break;
   
                           default:
                                   msg = ldap_int_msgtype2str( tag );
                                   break;
                           }
   
                           Debug( LDAP_DEBUG_ANY,
                                   "no request for response on ld %p msgid %d message type %s (tossing)\n",
                                   (void *)ld, id, msg );
   
                           goto retry_ber;
                   }
   
   #ifdef LDAP_CONNECTIONLESS
                   if ( LDAP_IS_UDP(ld) && isv2 ) {
                           ber_scanf(ber, "x{");
                   }
   nextresp2:
                   ;
   #endif
           }
   
         /* the message type */          /* the message type */
         if ( (tag = ber_peek_tag( ber, &len )) == LBER_ERROR ) {          tag = ber_peek_tag( ber, &len );
           if ( tag == LBER_ERROR ) {
                 ld->ld_errno = LDAP_DECODING_ERROR;                  ld->ld_errno = LDAP_DECODING_ERROR;
                   ber_free( ber, 1 );
                 return( -1 );                  return( -1 );
         }          }
   
           Debug( LDAP_DEBUG_TRACE,
                   "read1msg: ld %p msgid %d message type %s\n",
                   (void *)ld, id, ldap_int_msgtype2str( tag ) );
   
           if ( id == 0 ) {
                   /* unsolicited notification message (RFC 4511) */
                   if ( tag != LDAP_RES_EXTENDED ) {
                           /* toss it */
                           goto retry_ber;
   
                           /* strictly speaking, it's an error; from RFC 4511:
   
   4.4.  Unsolicited Notification
   
      An unsolicited notification is an LDAPMessage sent from the server to
      the client that is not in response to any LDAPMessage received by the
      server.  It is used to signal an extraordinary condition in the
      server or in the LDAP session between the client and the server.  The
      notification is of an advisory nature, and the server will not expect
      any response to be returned from the client.
   
      The unsolicited notification is structured as an LDAPMessage in which
      the messageID is zero and protocolOp is set to the extendedResp
      choice using the ExtendedResponse type (See Section 4.12).  The
      responseName field of the ExtendedResponse always contains an LDAPOID
      that is unique for this notification.
   
                            * however, since unsolicited responses
                            * are of advisory nature, better
                            * toss it, right now
                            */
   
   #if 0
                           ld->ld_errno = LDAP_DECODING_ERROR;
                           ber_free( ber, 1 );
                           return( -1 );
   #endif
                   }
   
                   lr = &dummy_lr;
           }
   
           id = lr->lr_origid;
         refer_cnt = 0;          refer_cnt = 0;
         hadref = simple_request = 0;          hadref = simple_request = 0;
         rc = -2;        /* default is to keep looking (no response found) */          rc = LDAP_MSG_X_KEEP_LOOKING;   /* default is to keep looking (no response found) */
         lr->lr_res_msgtype = tag;          lr->lr_res_msgtype = tag;
   
         if ( tag != LDAP_RES_SEARCH_ENTRY ) {          /*
                 if ( ld->ld_version >= LDAP_VERSION2 &&           * Check for V3 search reference
                         ( lr->lr_parent != NULL ||           */
                         ( LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_REFERRALS)          if ( tag == LDAP_RES_SEARCH_REFERENCE ) {
                                 != LDAP_OPT_OFF ) ) )                  if ( ld->ld_version > LDAP_VERSION2 ) {
                           /* This is a V3 search reference */
                           if ( LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_REFERRALS) ||
                                           lr->lr_parent != NULL )
                           {
                                   char **refs = NULL;
                                   tmpber = *ber;
   
                                   /* Get the referral list */
                                   if ( ber_scanf( &tmpber, "{v}", &refs ) == LBER_ERROR ) {
                                           rc = LDAP_DECODING_ERROR;
   
                                   } else {
                                           /* Note: refs array is freed by ldap_chase_v3referrals */
                                           refer_cnt = ldap_chase_v3referrals( ld, lr, refs,
                                                   1, &lr->lr_res_error, &hadref );
                                           if ( refer_cnt > 0 ) {
                                                   /* successfully chased reference */
                                                   /* If haven't got end search, set chasing referrals */
                                                   if ( lr->lr_status != LDAP_REQST_COMPLETED ) {
                                                           lr->lr_status = LDAP_REQST_CHASINGREFS;
                                                           Debug( LDAP_DEBUG_TRACE,
                                                                   "read1msg:  search ref chased, "
                                                                   "mark request chasing refs, "
                                                                   "id = %d\n",
                                                                   lr->lr_msgid, 0, 0 );
                                                   }
                                           }
                                   }
                           }
                   }
   
           } else if ( tag != LDAP_RES_SEARCH_ENTRY && tag != LDAP_RES_INTERMEDIATE ) {
                   /* All results that just return a status, i.e. don't return data
                    * go through the following code.  This code also chases V2 referrals
                    * and checks if all referrals have been chased.
                    */
                   char            *lr_res_error = NULL;
   
                   tmpber = *ber;  /* struct copy */
                   if ( ber_scanf( &tmpber, "{eAA", &lderr,
                                   &lr->lr_res_matched, &lr_res_error )
                                   != LBER_ERROR )
                 {                  {
                         tmpber = *ber;  /* struct copy */                          if ( lr_res_error != NULL ) {
                         if ( ber_scanf( &tmpber, "{iaa}", &lderr,                                  if ( lr->lr_res_error != NULL ) {
                             &lr->lr_res_matched, &lr->lr_res_error )                                          (void)ldap_append_referral( ld, &lr->lr_res_error, lr_res_error );
                             != LBER_ERROR ) {                                          LDAP_FREE( (char *)lr_res_error );
                                 if ( lderr != LDAP_SUCCESS ) {  
                                         /* referrals are in error string */                                  } else {
                                         refer_cnt = ldap_chase_referrals( ld, lr,                                          lr->lr_res_error = lr_res_error;
                                             &lr->lr_res_error, &hadref );                                  }
                                 }                                  lr_res_error = NULL;
                           }
                                 /* save errno, message, and matched string */  
                                 if ( !hadref || lr->lr_res_error == NULL ) {                          /* Do we need to check for referrals? */
                                         lr->lr_res_errno = ( lderr ==                          if ( LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_REFERRALS) ||
                                         LDAP_PARTIAL_RESULTS ) ? LDAP_SUCCESS                                          lr->lr_parent != NULL )
                                         : lderr;                          {
                                 } else if ( ld->ld_errno != LDAP_SUCCESS ) {                                  char            **refs = NULL;
                                         lr->lr_res_errno = ld->ld_errno;                                  ber_len_t       len;
   
                                   /* Check if V3 referral */
                                   if ( ber_peek_tag( &tmpber, &len ) == LDAP_TAG_REFERRAL ) {
                                           if ( ld->ld_version > LDAP_VERSION2 ) {
                                                   /* Get the referral list */
                                                   if ( ber_scanf( &tmpber, "{v}", &refs) == LBER_ERROR) {
                                                           rc = LDAP_DECODING_ERROR;
                                                           lr->lr_status = LDAP_REQST_COMPLETED;
                                                           Debug( LDAP_DEBUG_TRACE,
                                                                   "read1msg: referral decode error, "
                                                                   "mark request completed, ld %p msgid %d\n",
                                                                   (void *)ld, lr->lr_msgid, 0 );
   
                                                   } else {
                                                           /* Chase the referral 
                                                            * refs array is freed by ldap_chase_v3referrals
                                                            */
                                                           refer_cnt = ldap_chase_v3referrals( ld, lr, refs,
                                                                   0, &lr->lr_res_error, &hadref );
                                                           lr->lr_status = LDAP_REQST_COMPLETED;
                                                           Debug( LDAP_DEBUG_TRACE,
                                                                   "read1msg: referral %s chased, "
                                                                   "mark request completed, ld %p msgid %d\n",
                                                                   refer_cnt > 0 ? "" : "not",
                                                                   (void *)ld, lr->lr_msgid);
                                                           if ( refer_cnt < 0 ) {
                                                                   refer_cnt = 0;
                                                           }
                                                   }
                                           }
                                 } else {                                  } else {
                                         lr->lr_res_errno = LDAP_PARTIAL_RESULTS;                                          switch ( lderr ) {
                                           case LDAP_SUCCESS:
                                           case LDAP_COMPARE_TRUE:
                                           case LDAP_COMPARE_FALSE:
                                                   break;
   
                                           default:
                                                   if ( lr->lr_res_error == NULL ) {
                                                           break;
                                                   }
   
                                                   /* pedantic, should never happen */
                                                   if ( lr->lr_res_error[ 0 ] == '\0' ) {
                                                           LDAP_FREE( lr->lr_res_error );
                                                           lr->lr_res_error = NULL;
                                                           break;  
                                                   }
   
                                                   /* V2 referrals are in error string */
                                                   refer_cnt = ldap_chase_referrals( ld, lr,
                                                           &lr->lr_res_error, -1, &hadref );
                                                   lr->lr_status = LDAP_REQST_COMPLETED;
                                                   Debug( LDAP_DEBUG_TRACE,
                                                           "read1msg:  V2 referral chased, "
                                                           "mark request completed, id = %d\n",
                                                           lr->lr_msgid, 0, 0 );
                                                   break;
                                           }
                                 }                                  }
 Debug( LDAP_DEBUG_TRACE,                          }
     "new result:  res_errno: %d, res_error: <%s>, res_matched: <%s>\n",  
     lr->lr_res_errno, lr->lr_res_error ? lr->lr_res_error : "",                          /* save errno, message, and matched string */
     lr->lr_res_matched ? lr->lr_res_matched : "" );                          if ( !hadref || lr->lr_res_error == NULL ) {
                                   lr->lr_res_errno =
                                           lderr == LDAP_PARTIAL_RESULTS
                                           ? LDAP_SUCCESS : lderr;
   
                           } else if ( ld->ld_errno != LDAP_SUCCESS ) {
                                   lr->lr_res_errno = ld->ld_errno;
   
                           } else {
                                   lr->lr_res_errno = LDAP_PARTIAL_RESULTS;
                         }                          }
                 }                  }
   
                   /* in any case, don't leave any lr_res_error 'round */
                   if ( lr_res_error ) {
                           LDAP_FREE( lr_res_error );
                   }
   
                 Debug( LDAP_DEBUG_TRACE,                  Debug( LDAP_DEBUG_TRACE,
                     "read1msg:  %d new referrals\n", refer_cnt, 0, 0 );                          "read1msg: ld %p %d new referrals\n",
                           (void *)ld, refer_cnt, 0 );
   
                 if ( refer_cnt != 0 ) { /* chasing referrals */                  if ( refer_cnt != 0 ) { /* chasing referrals */
                         ber_clear( ber, 1 );    /* gack! */                          ber_free( ber, 1 );
                           ber = NULL;
                         if ( refer_cnt < 0 ) {                          if ( refer_cnt < 0 ) {
                                   ldap_return_request( ld, lr, 0 );
                                 return( -1 );   /* fatal error */                                  return( -1 );   /* fatal error */
                         }                          }
                         lr->lr_status = LDAP_REQST_CHASINGREFS;                          lr->lr_res_errno = LDAP_SUCCESS; /* sucessfully chased referral */
                           if ( lr->lr_res_matched ) {
                                   LDAP_FREE( lr->lr_res_matched );
                                   lr->lr_res_matched = NULL;
                           }
   
                 } else {                  } else {
                         if ( lr->lr_outrefcnt <= 0 && lr->lr_parent == NULL ) {                          if ( lr->lr_outrefcnt <= 0 && lr->lr_parent == NULL ) {
                                 /* request without any referrals */                                  /* request without any referrals */
                                 simple_request = ( hadref ? 0 : 1 );                                  simple_request = ( hadref ? 0 : 1 );
   
                         } else {                          } else {
                                 /* request with referrals or child request */                                  /* request with referrals or child request */
                                 ber_clear( ber, 1 );    /* gack! */                                  ber_free( ber, 1 );
                                   ber = NULL;
                         }                          }
   
                           lr->lr_status = LDAP_REQST_COMPLETED; /* declare this request done */
                           Debug( LDAP_DEBUG_TRACE,
                                   "read1msg:  mark request completed, ld %p msgid %d\n",
                                   (void *)ld, lr->lr_msgid, 0);
                         while ( lr->lr_parent != NULL ) {                          while ( lr->lr_parent != NULL ) {
                                 merge_error_info( ld, lr->lr_parent, lr );                                  merge_error_info( ld, lr->lr_parent, lr );
   
Line 385  Debug( LDAP_DEBUG_TRACE, Line 874  Debug( LDAP_DEBUG_TRACE,
                                 }                                  }
                         }                          }
   
                         if ( lr->lr_outrefcnt <= 0 && lr->lr_parent == NULL ) {                          /* Check if all requests are finished, lr is now parent */
                           tmplr = lr;
                           if ( tmplr->lr_status == LDAP_REQST_COMPLETED ) {
                                   for ( tmplr = lr->lr_child;
                                           tmplr != NULL;
                                           tmplr = tmplr->lr_refnext )
                                   {
                                           if ( tmplr->lr_status != LDAP_REQST_COMPLETED ) break;
                                   }
                           }
   
                           /* This is the parent request if the request has referrals */
                           if ( lr->lr_outrefcnt <= 0 &&
                                   lr->lr_parent == NULL &&
                                   tmplr == NULL )
                           {
                                 id = lr->lr_msgid;                                  id = lr->lr_msgid;
                                 tag = lr->lr_res_msgtype;                                  tag = lr->lr_res_msgtype;
                                 Debug( LDAP_DEBUG_ANY, "request %ld done\n",                                  Debug( LDAP_DEBUG_TRACE, "request done: ld %p msgid %d\n",
                                     id, 0, 0 );                                          (void *)ld, id, 0 );
 Debug( LDAP_DEBUG_TRACE,                                  Debug( LDAP_DEBUG_TRACE,
 "res_errno: %d, res_error: <%s>, res_matched: <%s>\n",                                          "res_errno: %d, res_error: <%s>, "
 lr->lr_res_errno, lr->lr_res_error ? lr->lr_res_error : "",                                          "res_matched: <%s>\n",
 lr->lr_res_matched ? lr->lr_res_matched : "" );                                          lr->lr_res_errno,
                                           lr->lr_res_error ? lr->lr_res_error : "",
                                           lr->lr_res_matched ? lr->lr_res_matched : "" );
                                 if ( !simple_request ) {                                  if ( !simple_request ) {
                                         ber_clear( ber, 1 ); /* gack! */                                          ber_free( ber, 1 );
                                         if ( build_result_ber( ld, ber, lr )                                          ber = NULL;
                                             == LBER_ERROR ) {                                          if ( build_result_ber( ld, &ber, lr )
                                                 ld->ld_errno = LDAP_NO_MEMORY;                                              == LBER_ERROR )
                                           {
                                                 rc = -1; /* fatal error */                                                  rc = -1; /* fatal error */
                                         }                                          }
                                 }                                  }
   
                                 ldap_free_request( ld, lr );                                  if ( lr != &dummy_lr ) {
                                           ldap_return_request( ld, lr, 1 );
                                   }
                                   lr = NULL;
                         }                          }
   
                         if ( lc != NULL ) {                          /*
                                 ldap_free_connection( ld, lc, 0, 1 );                           * RF 4511 unsolicited (id == 0) responses
                            * shouldn't necessarily end the connection
                            */
                           if ( lc != NULL && id != 0 ) {
                                   --lc->lconn_refcnt;
                                   lc = NULL;
                         }                          }
                 }                  }
         }          }
   
         if ( ber->ber_buf == NULL ) {          if ( lr != NULL ) {
                   if ( lr != &dummy_lr ) {
                           ldap_return_request( ld, lr, 0 );
                   }
                   lr = NULL;
           }
   
           if ( ber == NULL ) {
                 return( rc );                  return( rc );
         }          }
   
           /* try to handle unsolicited responses as appropriate */
           if ( id == 0 && msgid > LDAP_RES_UNSOLICITED ) {
                   int     is_nod = 0;
   
                   tag = ber_peek_tag( &tmpber, &len );
   
                   /* we have a res oid */
                   if ( tag == LDAP_TAG_EXOP_RES_OID ) {
                           static struct berval    bv_nod = BER_BVC( LDAP_NOTICE_OF_DISCONNECTION );
                           struct berval           resoid = BER_BVNULL;
   
                           if ( ber_scanf( &tmpber, "m", &resoid ) == LBER_ERROR ) {
                                   ld->ld_errno = LDAP_DECODING_ERROR;
                                   ber_free( ber, 1 );
                                   return -1;
                           }
   
                           assert( !BER_BVISEMPTY( &resoid ) );
   
                           is_nod = ber_bvcmp( &resoid, &bv_nod ) == 0;
   
                           tag = ber_peek_tag( &tmpber, &len );
                   }
   
   #if 0 /* don't need right now */
                   /* we have res data */
                   if ( tag == LDAP_TAG_EXOP_RES_VALUE ) {
                           struct berval resdata;
   
                           if ( ber_scanf( &tmpber, "m", &resdata ) == LBER_ERROR ) {
                                   ld->ld_errno = LDAP_DECODING_ERROR;
                                   ber_free( ber, 0 );
                                   return ld->ld_errno;
                           }
   
                           /* use it... */
                   }
   #endif
   
                   /* handle RFC 4511 "Notice of Disconnection" locally */
   
                   if ( is_nod ) {
                           if ( tag == LDAP_TAG_EXOP_RES_VALUE ) {
                                   ld->ld_errno = LDAP_DECODING_ERROR;
                                   ber_free( ber, 1 );
                                   return -1;
                           }
   
                           /* get rid of the connection... */
                           if ( lc != NULL ) {
                                   --lc->lconn_refcnt;
                           }
   
                           /* need to return -1, because otherwise
                            * a valid result is expected */
                           return -1;
                   }
           }
   
         /* make a new ldap message */          /* make a new ldap message */
         if ( (new = (LDAPMessage *) calloc( 1, sizeof(LDAPMessage) ))          newmsg = (LDAPMessage *) LDAP_CALLOC( 1, sizeof(LDAPMessage) );
             == NULL ) {          if ( newmsg == NULL ) {
                 ld->ld_errno = LDAP_NO_MEMORY;                  ld->ld_errno = LDAP_NO_MEMORY;
                 return( -1 );                  return( -1 );
         }          }
         new->lm_msgid = (int)id;          newmsg->lm_msgid = (int)id;
         new->lm_msgtype = tag;          newmsg->lm_msgtype = tag;
         new->lm_ber = ber_dup( ber );          newmsg->lm_ber = ber;
         ber_clear( ber, 0 ); /* don't kill buffer */          newmsg->lm_chain_tail = newmsg;
   
 #ifndef LDAP_NOCACHE  #ifdef LDAP_CONNECTIONLESS
                 if ( ld->ld_cache != NULL ) {          /* CLDAP replies all fit in a single datagram. In LDAPv2 RFC1798
                         ldap_add_result_to_cache( ld, new );           * the responses are all a sequence wrapped in one message. In
            * LDAPv3 each response is in its own message. The datagram must
            * end with a SearchResult. We can't just parse each response in
            * separate calls to try_read1msg because the header info is only
            * present at the beginning of the datagram, not at the beginning
            * of each response. So parse all the responses at once and queue
            * them up, then pull off the first response to return to the
            * caller when all parsing is complete.
            */
           if ( LDAP_IS_UDP(ld) ) {
                   /* If not a result, look for more */
                   if ( tag != LDAP_RES_SEARCH_RESULT ) {
                           int ok = 0;
                           moremsgs = 1;
                           if (isv2) {
                                   /* LDAPv2: dup the current ber, skip past the current
                                    * response, and see if there are any more after it.
                                    */
                                   ber = ber_dup( ber );
                                   ber_scanf( ber, "x" );
                                   if ( ber_peek_tag( ber, &len ) != LBER_DEFAULT ) {
                                           /* There's more - dup the ber buffer so they can all be
                                            * individually freed by ldap_msgfree.
                                            */
                                           struct berval bv;
                                           ber_get_option( ber, LBER_OPT_BER_REMAINING_BYTES, &len );
                                           bv.bv_val = LDAP_MALLOC( len );
                                           if ( bv.bv_val ) {
                                                   ok = 1;
                                                   ber_read( ber, bv.bv_val, len );
                                                   bv.bv_len = len;
                                                   ber_init2( ber, &bv, ld->ld_lberoptions );
                                           }
                                   }
                           } else {
                                   /* LDAPv3: Just allocate a new ber. Since this is a buffered
                                    * datagram, if the sockbuf is readable we still have data
                                    * to parse.
                                    */
                                   ber = ldap_alloc_ber_with_options( ld );
                                   if ( ber_sockbuf_ctrl( lc->lconn_sb, LBER_SB_OPT_DATA_READY, NULL ) ) ok = 1;
                           }
                           /* set up response chain */
                           if ( tmp == NULL ) {
                                   newmsg->lm_next = ld->ld_responses;
                                   ld->ld_responses = newmsg;
                                   chain_head = newmsg;
                           } else {
                                   tmp->lm_chain = newmsg;
                           }
                           chain_head->lm_chain_tail = newmsg;
                           tmp = newmsg;
                           /* "ok" means there's more to parse */
                           if ( ok ) {
                                   if ( isv2 ) {
                                           goto nextresp2;
   
                                   } else {
                                           goto nextresp3;
                                   }
                           } else {
                                   /* got to end of datagram without a SearchResult. Free
                                    * our dup'd ber, but leave any buffer alone. For v2 case,
                                    * the previous response is still using this buffer. For v3,
                                    * the new ber has no buffer to free yet.
                                    */
                                   ber_free( ber, 0 );
                                   return -1;
                           }
                   } else if ( moremsgs ) {
                   /* got search result, and we had multiple responses in 1 datagram.
                    * stick the result onto the end of the chain, and then pull the
                    * first response off the head of the chain.
                    */
                           tmp->lm_chain = newmsg;
                           chain_head->lm_chain_tail = newmsg;
                           *result = chkResponseList( ld, msgid, all );
                           ld->ld_errno = LDAP_SUCCESS;
                           return( (*result)->lm_msgtype );
                 }                  }
 #endif /* LDAP_NOCACHE */          }
   #endif /* LDAP_CONNECTIONLESS */
   
         /* is this the one we're looking for? */          /* is this the one we're looking for? */
         if ( msgid == LDAP_RES_ANY || id == msgid ) {          if ( msgid == LDAP_RES_ANY || id == msgid ) {
                 if ( all == 0                  if ( all == LDAP_MSG_ONE
                     || (new->lm_msgtype != LDAP_RES_SEARCH_RESULT                          || ( newmsg->lm_msgtype != LDAP_RES_SEARCH_RESULT
                     && new->lm_msgtype != LDAP_RES_SEARCH_ENTRY) ) {                                  && newmsg->lm_msgtype != LDAP_RES_SEARCH_ENTRY
                         *result = new;                                  && newmsg->lm_msgtype != LDAP_RES_INTERMEDIATE
                                   && newmsg->lm_msgtype != LDAP_RES_SEARCH_REFERENCE ) )
                   {
                           *result = newmsg;
                         ld->ld_errno = LDAP_SUCCESS;                          ld->ld_errno = LDAP_SUCCESS;
                         return( tag );                          return( tag );
                 } else if ( new->lm_msgtype == LDAP_RES_SEARCH_RESULT) {  
                   } else if ( newmsg->lm_msgtype == LDAP_RES_SEARCH_RESULT) {
                         foundit = 1;    /* return the chain later */                          foundit = 1;    /* return the chain later */
                 }                  }
         }          }
Line 452  lr->lr_res_matched ? lr->lr_res_matched Line 1116  lr->lr_res_matched ? lr->lr_res_matched
          * search response.           * search response.
          */           */
   
         prev = NULLMSG;          prev = NULL;
         for ( l = ld->ld_responses; l != NULLMSG; l = l->lm_next ) {          for ( l = ld->ld_responses; l != NULL; l = l->lm_next ) {
                 if ( l->lm_msgid == new->lm_msgid )                  if ( l->lm_msgid == newmsg->lm_msgid ) {
                         break;                          break;
                   }
                 prev = l;                  prev = l;
         }          }
   
         /* not part of an existing search response */          /* not part of an existing search response */
         if ( l == NULLMSG ) {          if ( l == NULL ) {
                 if ( foundit ) {                  if ( foundit ) {
                         *result = new;                          *result = newmsg;
                         ld->ld_errno = LDAP_SUCCESS;                          goto exit;
                         return( tag );  
                 }                  }
   
                 new->lm_next = ld->ld_responses;                  newmsg->lm_next = ld->ld_responses;
                 ld->ld_responses = new;                  ld->ld_responses = newmsg;
                 return( -2 );   /* continue looking */                  goto exit;
         }          }
   
         Debug( LDAP_DEBUG_TRACE, "adding response id %d type %d:\n",          Debug( LDAP_DEBUG_TRACE, "adding response ld %p msgid %d type %ld:\n",
             new->lm_msgid, new->lm_msgtype, 0 );                  (void *)ld, newmsg->lm_msgid, (long) newmsg->lm_msgtype );
   
         /* part of a search response - add to end of list of entries */          /* part of a search response - add to end of list of entries */
         for ( tmp = l; tmp->lm_chain != NULLMSG &&          l->lm_chain_tail->lm_chain = newmsg;
             tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_ENTRY;          l->lm_chain_tail = newmsg;
             tmp = tmp->lm_chain )  
                 ;       /* NULL */  
         tmp->lm_chain = new;  
   
         /* return the whole chain if that's what we were looking for */          /* return the whole chain if that's what we were looking for */
         if ( foundit ) {          if ( foundit ) {
                 if ( prev == NULLMSG )                  if ( prev == NULL ) {
                         ld->ld_responses = l->lm_next;                          ld->ld_responses = l->lm_next;
                 else                  } else {
                         prev->lm_next = l->lm_next;                          prev->lm_next = l->lm_next;
                   }
                 *result = l;                  *result = l;
           }
   
   exit:
           if ( foundit ) {
                 ld->ld_errno = LDAP_SUCCESS;                  ld->ld_errno = LDAP_SUCCESS;
 #ifdef LDAP_WORLD_P16  
                 /*  
                  * XXX questionable fix; see text for [P16] on  
                  * http://www.critical-angle.com/ldapworld/patch/  
                  *  
                  * inclusion of this patch causes searchs to hang on  
                  * multiple platforms  
                  */  
                 return( l->lm_msgtype );  
 #else   /* LDAP_WORLD_P16 */  
                 return( tag );                  return( tag );
 #endif  /* !LDAP_WORLD_P16 */  
         }          }
           if ( lc && ber_sockbuf_ctrl( lc->lconn_sb, LBER_SB_OPT_DATA_READY, NULL ) ) {
         return( -2 );   /* continue looking */                  goto retry;
           }
           return( LDAP_MSG_X_KEEP_LOOKING );      /* continue looking */
 }  }
   
   
 static unsigned long  static ber_tag_t
 build_result_ber( LDAP *ld, BerElement *ber, LDAPRequest *lr )  build_result_ber( LDAP *ld, BerElement **bp, LDAPRequest *lr )
 {  {
         unsigned long   len;          ber_len_t       len;
         long            along;          ber_tag_t       tag;
           ber_int_t       along;
           BerElement *ber;
   
           *bp = NULL;
           ber = ldap_alloc_ber_with_options( ld );
   
           if( ber == NULL ) {
                   ld->ld_errno = LDAP_NO_MEMORY;
                   return LBER_ERROR;
           }
   
         ber_init_w_nullc( ber, 0 );  
         ldap_set_ber_options( ld, ber );  
         if ( ber_printf( ber, "{it{ess}}", lr->lr_msgid,          if ( ber_printf( ber, "{it{ess}}", lr->lr_msgid,
             (unsigned long) lr->lr_res_msgtype, lr->lr_res_errno,                  lr->lr_res_msgtype, lr->lr_res_errno,
             lr->lr_res_matched ? lr->lr_res_matched : "",                  lr->lr_res_matched ? lr->lr_res_matched : "",
             lr->lr_res_error ? lr->lr_res_error : "" ) == -1 ) {                  lr->lr_res_error ? lr->lr_res_error : "" ) == -1 )
           {
                   ld->ld_errno = LDAP_ENCODING_ERROR;
                   ber_free( ber, 1 );
                 return( LBER_ERROR );                  return( LBER_ERROR );
         }          }
   
         ber_reset( ber, 1 );          ber_reset( ber, 1 );
   
         if ( ber_skip_tag( ber, &len ) == LBER_ERROR ) {          if ( ber_skip_tag( ber, &len ) == LBER_ERROR ) {
                   ld->ld_errno = LDAP_DECODING_ERROR;
                   ber_free( ber, 1 );
                 return( LBER_ERROR );                  return( LBER_ERROR );
         }          }
   
         if ( ber_get_int( ber, &along ) == LBER_ERROR ) {          if ( ber_get_enum( ber, &along ) == LBER_ERROR ) {
                   ld->ld_errno = LDAP_DECODING_ERROR;
                   ber_free( ber, 1 );
                 return( LBER_ERROR );                  return( LBER_ERROR );
         }          }
   
         return( ber_peek_tag( ber, &len ));          tag = ber_peek_tag( ber, &len );
   
           if ( tag == LBER_ERROR ) {
                   ld->ld_errno = LDAP_DECODING_ERROR;
                   ber_free( ber, 1 );
                   return( LBER_ERROR );
           }
   
           *bp = ber;
           return tag;
 }  }
   
   
 static void  
 merge_error_info( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr )  
 {  
 /*  /*
  * Merge error information in "lr" with "parentr" error code and string.   * Merge error information in "lr" with "parentr" error code and string.
  */   */
   static void
   merge_error_info( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr )
   {
         if ( lr->lr_res_errno == LDAP_PARTIAL_RESULTS ) {          if ( lr->lr_res_errno == LDAP_PARTIAL_RESULTS ) {
                 parentr->lr_res_errno = lr->lr_res_errno;                  parentr->lr_res_errno = lr->lr_res_errno;
                 if ( lr->lr_res_error != NULL ) {                  if ( lr->lr_res_error != NULL ) {
                         (void)ldap_append_referral( ld, &parentr->lr_res_error,                          (void)ldap_append_referral( ld, &parentr->lr_res_error,
                             lr->lr_res_error );                                  lr->lr_res_error );
                 }                  }
   
         } else if ( lr->lr_res_errno != LDAP_SUCCESS &&          } else if ( lr->lr_res_errno != LDAP_SUCCESS &&
             parentr->lr_res_errno == LDAP_SUCCESS ) {                  parentr->lr_res_errno == LDAP_SUCCESS )
           {
                 parentr->lr_res_errno = lr->lr_res_errno;                  parentr->lr_res_errno = lr->lr_res_errno;
                 if ( parentr->lr_res_error != NULL ) {                  if ( parentr->lr_res_error != NULL ) {
                         free( parentr->lr_res_error );                          LDAP_FREE( parentr->lr_res_error );
                 }                  }
                 parentr->lr_res_error = lr->lr_res_error;                  parentr->lr_res_error = lr->lr_res_error;
                 lr->lr_res_error = NULL;                  lr->lr_res_error = NULL;
                 if ( LDAP_NAME_ERROR( lr->lr_res_errno )) {                  if ( LDAP_NAME_ERROR( lr->lr_res_errno ) ) {
                         if ( parentr->lr_res_matched != NULL ) {                          if ( parentr->lr_res_matched != NULL ) {
                                 free( parentr->lr_res_matched );                                  LDAP_FREE( parentr->lr_res_matched );
                         }                          }
                         parentr->lr_res_matched = lr->lr_res_matched;                          parentr->lr_res_matched = lr->lr_res_matched;
                         lr->lr_res_matched = NULL;                          lr->lr_res_matched = NULL;
Line 566  merge_error_info( LDAP *ld, LDAPRequest Line 1250  merge_error_info( LDAP *ld, LDAPRequest
         }          }
   
         Debug( LDAP_DEBUG_TRACE, "merged parent (id %d) error info:  ",          Debug( LDAP_DEBUG_TRACE, "merged parent (id %d) error info:  ",
             parentr->lr_msgid, 0, 0 );                  parentr->lr_msgid, 0, 0 );
         Debug( LDAP_DEBUG_TRACE, "result errno %d, error <%s>, matched <%s>\n",          Debug( LDAP_DEBUG_TRACE, "result errno %d, error <%s>, matched <%s>\n",
             parentr->lr_res_errno, parentr->lr_res_error ?                  parentr->lr_res_errno,
             parentr->lr_res_error : "", parentr->lr_res_matched ?                  parentr->lr_res_error ?  parentr->lr_res_error : "",
             parentr->lr_res_matched : "" );                  parentr->lr_res_matched ?  parentr->lr_res_matched : "" );
 }  }
   
   
Line 579  int Line 1263  int
 ldap_msgtype( LDAPMessage *lm )  ldap_msgtype( LDAPMessage *lm )
 {  {
         assert( lm != NULL );          assert( lm != NULL );
         return ( lm == NULL ) ? lm->lm_msgtype : -1;          return ( lm != NULL ) ? (int)lm->lm_msgtype : -1;
 }  }
   
   
Line 588  ldap_msgid( LDAPMessage *lm ) Line 1272  ldap_msgid( LDAPMessage *lm )
 {  {
         assert( lm != NULL );          assert( lm != NULL );
   
         return ( lm == NULL ) ? lm->lm_msgid : -1;          return ( lm != NULL ) ? lm->lm_msgid : -1;
 }  }
   
   
   const char *
   ldap_int_msgtype2str( ber_tag_t tag )
   {
           switch( tag ) {
           case LDAP_RES_ADD: return "add";
           case LDAP_RES_BIND: return "bind";
           case LDAP_RES_COMPARE: return "compare";
           case LDAP_RES_DELETE: return "delete";
           case LDAP_RES_EXTENDED: return "extended-result";
           case LDAP_RES_INTERMEDIATE: return "intermediate";
           case LDAP_RES_MODIFY: return "modify";
           case LDAP_RES_RENAME: return "rename";
           case LDAP_RES_SEARCH_ENTRY: return "search-entry";
           case LDAP_RES_SEARCH_REFERENCE: return "search-reference";
           case LDAP_RES_SEARCH_RESULT: return "search-result";
           }
           return "unknown";
   }
   
 int  int
 ldap_msgfree( LDAPMessage *lm )  ldap_msgfree( LDAPMessage *lm )
 {  {
         LDAPMessage     *next;          LDAPMessage     *next;
         int             type = 0;          int             type = 0;
   
         assert( lm != NULL );  
   
         Debug( LDAP_DEBUG_TRACE, "ldap_msgfree\n", 0, 0, 0 );          Debug( LDAP_DEBUG_TRACE, "ldap_msgfree\n", 0, 0, 0 );
   
         for ( ; lm != NULLMSG; lm = next ) {          for ( ; lm != NULL; lm = next ) {
                 next = lm->lm_chain;                  next = lm->lm_chain;
                 type = lm->lm_msgtype;                  type = lm->lm_msgtype;
                 ber_free( lm->lm_ber, 1 );                  ber_free( lm->lm_ber, 1 );
                 free( (char *) lm );                  LDAP_FREE( (char *) lm );
         }          }
   
         return( type );          return type;
 }  }
   
 /*  /*
Line 621  int Line 1322  int
 ldap_msgdelete( LDAP *ld, int msgid )  ldap_msgdelete( LDAP *ld, int msgid )
 {  {
         LDAPMessage     *lm, *prev;          LDAPMessage     *lm, *prev;
           int             rc = 0;
   
         assert( ld != NULL );          assert( ld != NULL );
   
         Debug( LDAP_DEBUG_TRACE, "ldap_msgdelete\n", 0, 0, 0 );          Debug( LDAP_DEBUG_TRACE, "ldap_msgdelete ld=%p msgid=%d\n",
                   (void *)ld, msgid, 0 );
   
         prev = NULLMSG;  #ifdef LDAP_R_COMPILE
         for ( lm = ld->ld_responses; lm != NULLMSG; lm = lm->lm_next ) {          ldap_pvt_thread_mutex_lock( &ld->ld_res_mutex );
                 if ( lm->lm_msgid == msgid )  #endif
           prev = NULL;
           for ( lm = ld->ld_responses; lm != NULL; lm = lm->lm_next ) {
                   if ( lm->lm_msgid == msgid ) {
                         break;                          break;
                   }
                 prev = lm;                  prev = lm;
         }          }
   
         if ( lm == NULLMSG )          if ( lm == NULL ) {
                 return( -1 );                  rc = -1;
   
         if ( prev == NULLMSG )          } else {
                 ld->ld_responses = lm->lm_next;                  if ( prev == NULL ) {
         else                          ld->ld_responses = lm->lm_next;
                 prev->lm_next = lm->lm_next;                  } else {
                           prev->lm_next = lm->lm_next;
                   }
           }
   #ifdef LDAP_R_COMPILE
           ldap_pvt_thread_mutex_unlock( &ld->ld_res_mutex );
   #endif
           if ( lm ) {
                   switch ( ldap_msgfree( lm ) ) {
                   case LDAP_RES_SEARCH_ENTRY:
                   case LDAP_RES_SEARCH_REFERENCE:
                   case LDAP_RES_INTERMEDIATE:
                           rc = -1;
                           break;
   
         if ( ldap_msgfree( lm ) == LDAP_RES_SEARCH_ENTRY )                  default:
                 return( -1 );                          break;
                   }
           }
   
         return( 0 );          return rc;
 }  }
   
   
 /*  /*
  * return 1 if message msgid is waiting to be abandoned, 0 otherwise   * ldap_abandoned
    *
    * return the location of the message id in the array of abandoned
    * message ids, or -1
    *
    * expects ld_res_mutex to be locked
  */   */
 static int  static int
 ldap_abandoned( LDAP *ld, int msgid )  ldap_abandoned( LDAP *ld, ber_int_t msgid, int *idxp )
 {  {
         int     i;  #ifdef LDAP_R_COMPILE
           LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex );
         if ( ld->ld_abandoned == NULL )  #endif
                 return( 0 );  
   
         for ( i = 0; ld->ld_abandoned[i] != -1; i++ )          assert( idxp != NULL );
                 if ( ld->ld_abandoned[i] == msgid )          assert( msgid >= 0 );
                         return( 1 );  
   
         return( 0 );          return ldap_int_bisect_find( ld->ld_abandoned, ld->ld_nabandoned, msgid, idxp );
 }  }
   
   /*
    * ldap_mark_abandoned
    *
    * expects ld_res_mutex to be locked
    */
 static int  static int
 ldap_mark_abandoned( LDAP *ld, int msgid )  ldap_mark_abandoned( LDAP *ld, ber_int_t msgid, int idx )
 {  
         int     i;  
   
         if ( ld->ld_abandoned == NULL )  
                 return( -1 );  
   
         for ( i = 0; ld->ld_abandoned[i] != -1; i++ )  
                 if ( ld->ld_abandoned[i] == msgid )  
                         break;  
   
         if ( ld->ld_abandoned[i] == -1 )  
                 return( -1 );  
   
         for ( ; ld->ld_abandoned[i] != -1; i++ ) {  
                 ld->ld_abandoned[i] = ld->ld_abandoned[i + 1];  
         }  
   
         return( 0 );  
 }  
   
   
 #ifdef LDAP_CONNECTIONLESS  
 int  
 cldap_getmsg( LDAP *ld, struct timeval *timeout, BerElement *ber )  
 {  {
         int             rc;  #ifdef LDAP_R_COMPILE
         unsigned long   tag, len;          LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex );
   #endif
   
         if ( ! ber_pvt_sb_data_ready(&ld->ld_sb) ) {          /* NOTE: those assertions are repeated in ldap_int_bisect_delete() */
                 rc = ldap_select1( ld, timeout );          assert( idx >= 0 );
                 if ( rc == -1 || rc == 0 ) {          assert( (unsigned) idx < ld->ld_nabandoned );
                         ld->ld_errno = (rc == -1 ? LDAP_SERVER_DOWN :          assert( ld->ld_abandoned[ idx ] == msgid );
                             LDAP_TIMEOUT);  
                         return( rc );  
                 }  
         }  
   
         /* get the next message */          return ldap_int_bisect_delete( &ld->ld_abandoned, &ld->ld_nabandoned,
         if ( (tag = ber_get_next( &ld->ld_sb, &len, ber ))                  msgid, idx );
             != LDAP_TAG_MESSAGE ) {  
                 ld->ld_errno = (tag == LBER_DEFAULT ? LDAP_SERVER_DOWN :  
                     LDAP_LOCAL_ERROR);  
                 return( -1 );  
         }  
   
         return( tag );  
 }  }
 #endif /* LDAP_CONNECTIONLESS */  

Removed from v.1.26  
changed lines
  Added in v.1.124.2.21


______________
© Copyright 1998-2020, OpenLDAP Foundation, info@OpenLDAP.org