Back to index

lightning-sunbird  0.9+nobinonly
result.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is Mozilla Communicator client code, released
00015  * March 31, 1998.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 /*
00038  *  Copyright (c) 1990 Regents of the University of Michigan.
00039  *  All rights reserved.
00040  */
00041 /*
00042  *  result.c - wait for an ldap result
00043  */
00044 
00045 #if 0
00046 #ifndef lint 
00047 static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
00048 #endif
00049 #endif
00050 
00051 #include "ldap-int.h"
00052 
00053 static int check_response_queue( LDAP *ld, int msgid, int all,
00054        int do_abandon_check, LDAPMessage **result );
00055 static int ldap_abandoned( LDAP *ld, int msgid );
00056 static int ldap_mark_abandoned( LDAP *ld, int msgid );
00057 static int wait4msg( LDAP *ld, int msgid, int all, int unlock_permitted,
00058        struct timeval *timeout, LDAPMessage **result );
00059 static int read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb, LDAPConn *lc,
00060        LDAPMessage **result );
00061 static void check_for_refs( LDAP *ld, LDAPRequest *lr, BerElement *ber,
00062        int ldapversion, int *totalcountp, int *chasingcountp );
00063 static int build_result_ber( LDAP *ld, BerElement **berp, LDAPRequest *lr );
00064 static void merge_error_info( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr );
00065 #if defined( CLDAP )
00066 static int cldap_select1( LDAP *ld, struct timeval *timeout );
00067 #endif
00068 static void link_pend( LDAP *ld, LDAPPend *lp );
00069 #if 0 /* these functions are no longer used */
00070 static void unlink_pend( LDAP *ld, LDAPPend *lp );
00071 static int unlink_msg( LDAP *ld, int msgid, int all );
00072 #endif /* 0 */
00073 
00074 /*
00075  * ldap_result - wait for an ldap result response to a message from the
00076  * ldap server.  If msgid is -1, any message will be accepted, otherwise
00077  * ldap_result will wait for a response with msgid.  If all is 0 the
00078  * first message with id msgid will be accepted, otherwise, ldap_result
00079  * will wait for all responses with id msgid and then return a pointer to
00080  * the entire list of messages.  This is only useful for search responses,
00081  * which can be of two message types (zero or more entries, followed by an
00082  * ldap result).  The type of the first message received is returned.
00083  * When waiting, any messages that have been abandoned are discarded.
00084  *
00085  * Example:
00086  *     ldap_result( s, msgid, all, timeout, result )
00087  */
00088 int
00089 LDAP_CALL
00090 ldap_result(
00091     LDAP             *ld,
00092     int              msgid,
00093     int              all,
00094     struct timeval   *timeout,
00095     LDAPMessage             **result
00096 )
00097 {
00098        int           rc;
00099 
00100        LDAPDebug( LDAP_DEBUG_TRACE, "ldap_result\n", 0, 0, 0 );
00101 
00102        if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
00103               return( -1 ); /* punt */
00104        }
00105 
00106        LDAP_MUTEX_LOCK( ld, LDAP_RESULT_LOCK );
00107 
00108        rc = nsldapi_result_nolock(ld, msgid, all, 1, timeout, result);
00109 
00110        LDAP_MUTEX_UNLOCK( ld, LDAP_RESULT_LOCK );
00111 
00112        return( rc );
00113 }
00114 
00115 
00116 int
00117 nsldapi_result_nolock( LDAP *ld, int msgid, int all, int unlock_permitted,
00118     struct timeval *timeout, LDAPMessage **result )
00119 {
00120        int           rc;
00121 
00122        LDAPDebug( LDAP_DEBUG_TRACE,
00123               "nsldapi_result_nolock (msgid=%d, all=%d)\n", msgid, all, 0 );
00124 
00125        /*
00126         * First, look through the list of responses we have received on
00127         * this association and see if the response we're interested in
00128         * is there.  If it is, return it.  If not, call wait4msg() to
00129         * wait until it arrives or timeout occurs.
00130         */
00131 
00132        if ( result == NULL ) {
00133               LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
00134               return( -1 );
00135        }
00136 
00137        if ( check_response_queue( ld, msgid, all, 1, result ) != 0 ) {
00138               LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, NULL );
00139               rc = (*result)->lm_msgtype;
00140        } else {
00141               rc = wait4msg( ld, msgid, all, unlock_permitted, timeout,
00142                   result );
00143        }
00144 
00145        /*
00146         * XXXmcs should use cache function pointers to hook in memcache
00147         */
00148        if ( ld->ld_memcache != NULL && NSLDAPI_SEARCH_RELATED_RESULT( rc ) &&
00149             !((*result)->lm_fromcache )) {
00150               ldap_memcache_append( ld, (*result)->lm_msgid,
00151                   (all || NSLDAPI_IS_SEARCH_RESULT( rc )), *result );
00152        }
00153 
00154        return( rc );
00155 }
00156 
00157 
00158 /*
00159  * Look through the list of queued responses for a message that matches the
00160  * criteria in the msgid and all parameters.  msgid == LDAP_RES_ANY matches
00161  * all ids.
00162  *
00163  * If an appropriate message is found, a non-zero value is returned and the
00164  * message is dequeued and assigned to *result.
00165  *
00166  * If not, *result is set to NULL and this function returns 0.
00167  */
00168 static int
00169 check_response_queue( LDAP *ld, int msgid, int all, int do_abandon_check,
00170     LDAPMessage **result )
00171 {
00172        LDAPMessage   *lm, *lastlm, *nextlm;
00173        LDAPRequest   *lr;
00174 
00175        LDAPDebug( LDAP_DEBUG_TRACE,
00176            "=> check_response_queue (msgid=%d, all=%d)\n", msgid, all, 0 );
00177 
00178        *result = NULL;
00179        lastlm = NULL;
00180        LDAP_MUTEX_LOCK( ld, LDAP_RESP_LOCK );
00181        for ( lm = ld->ld_responses; lm != NULL; lm = nextlm ) {
00182               nextlm = lm->lm_next;
00183 
00184               if ( do_abandon_check && ldap_abandoned( ld, lm->lm_msgid ) ) {
00185                      ldap_mark_abandoned( ld, lm->lm_msgid );
00186 
00187                      if ( lastlm == NULL ) {
00188                             ld->ld_responses = lm->lm_next;
00189                      } else {
00190                             lastlm->lm_next = nextlm;
00191                      }
00192 
00193                      ldap_msgfree( lm );
00194 
00195                      continue;
00196               }
00197 
00198               if ( msgid == LDAP_RES_ANY || lm->lm_msgid == msgid ) {
00199                      LDAPMessage   *tmp;
00200 
00201                      if ( all == 0
00202                          || (lm->lm_msgtype != LDAP_RES_SEARCH_RESULT
00203                          && lm->lm_msgtype != LDAP_RES_SEARCH_REFERENCE
00204                          && lm->lm_msgtype != LDAP_RES_SEARCH_ENTRY) )
00205                             break;
00206 
00207                      for ( tmp = lm; tmp != NULL; tmp = tmp->lm_chain ) {
00208                             if ( tmp->lm_msgtype == LDAP_RES_SEARCH_RESULT )
00209                                    break;
00210                      }
00211 
00212                      if ( tmp == NULL ) {
00213                             LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
00214                             LDAPDebug( LDAP_DEBUG_TRACE,
00215                                 "<= check_response_queue NOT FOUND\n",
00216                                 0, 0, 0 );
00217                             return( 0 );  /* no message to return */
00218                      }
00219 
00220                      break;
00221               }
00222               lastlm = lm;
00223        }
00224 
00225        /*
00226         * if we did not find a message OR if the one we found is a result for
00227         * a request that is still pending, return failure.
00228         */
00229        if ( lm == NULL 
00230              || (( lr = nsldapi_find_request_by_msgid( ld, lm->lm_msgid ))
00231                  != NULL && lr->lr_outrefcnt > 0 )) {
00232               LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
00233               LDAPDebug( LDAP_DEBUG_TRACE,
00234                   "<= check_response_queue NOT FOUND\n",
00235                   0, 0, 0 );
00236               return( 0 );  /* no message to return */
00237        }
00238 
00239        if ( all == 0 ) {
00240               if ( lm->lm_chain == NULL ) {
00241                      if ( lastlm == NULL ) {
00242                             ld->ld_responses = lm->lm_next;
00243                      } else {
00244                             lastlm->lm_next = lm->lm_next;
00245                      }
00246               } else {
00247                      if ( lastlm == NULL ) {
00248                             ld->ld_responses = lm->lm_chain;
00249                             ld->ld_responses->lm_next = lm->lm_next;
00250                      } else {
00251                             lastlm->lm_next = lm->lm_chain;
00252                             lastlm->lm_next->lm_next = lm->lm_next;
00253                      }
00254               }
00255        } else {
00256               if ( lastlm == NULL ) {
00257                      ld->ld_responses = lm->lm_next;
00258               } else {
00259                      lastlm->lm_next = lm->lm_next;
00260               }
00261        }
00262 
00263        if ( all == 0 ) {
00264               lm->lm_chain = NULL;
00265        }
00266        lm->lm_next = NULL;
00267        LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
00268 
00269        *result = lm;
00270        LDAPDebug( LDAP_DEBUG_TRACE,
00271            "<= check_response_queue returning msgid %d type %d\n",
00272            lm->lm_msgid, lm->lm_msgtype, 0 );
00273        return( 1 );  /* a message was found and returned in *result */
00274 }
00275 
00276 
00277 static int
00278 wait4msg( LDAP *ld, int msgid, int all, int unlock_permitted,
00279        struct timeval *timeout, LDAPMessage **result )
00280 {
00281        int           rc;
00282        struct timeval       tv, *tvp;
00283        long          start_time = 0, tmp_time;
00284        LDAPConn      *lc, *nextlc;
00285        LDAPRequest   *lr;
00286 
00287 #ifdef LDAP_DEBUG
00288        if ( timeout == NULL ) {
00289               LDAPDebug( LDAP_DEBUG_TRACE, "wait4msg (infinite timeout)\n",
00290                   0, 0, 0 );
00291        } else {
00292               LDAPDebug( LDAP_DEBUG_TRACE, "wait4msg (timeout %ld sec, %ld usec)\n",
00293                   timeout->tv_sec, timeout->tv_usec, 0 );
00294        }
00295 #endif /* LDAP_DEBUG */
00296 
00297        /* check the cache */
00298        if ( ld->ld_cache_on && ld->ld_cache_result != NULL ) {
00299               /* if ( unlock_permitted ) LDAP_MUTEX_UNLOCK( ld ); */
00300               LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK );
00301               rc = (ld->ld_cache_result)( ld, msgid, all, timeout, result );
00302               LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
00303               /* if ( unlock_permitted ) LDAP_MUTEX_LOCK( ld ); */
00304               if ( rc != 0 ) {
00305                      return( rc );
00306               }
00307               if ( ld->ld_cache_strategy == LDAP_CACHE_LOCALDB ) {
00308                      LDAP_SET_LDERRNO( ld, LDAP_TIMEOUT, NULL, NULL );
00309                      return( 0 );  /* timeout */
00310               }
00311        }
00312 
00313        /*
00314         * if we are looking for a specific msgid, check to see if it is
00315         * associated with a dead connection and return an error if so.
00316         */
00317        if ( msgid != LDAP_RES_ANY && msgid != LDAP_RES_UNSOLICITED ) {
00318               LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
00319               if (( lr = nsldapi_find_request_by_msgid( ld, msgid ))
00320                   == NULL ) {
00321                      LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
00322                      LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL,
00323                             nsldapi_strdup( "unknown message id" ));
00324                      return( -1 ); /* could not find request for msgid */
00325               }
00326               if ( lr->lr_conn != NULL &&
00327                   lr->lr_conn->lconn_status == LDAP_CONNST_DEAD ) {
00328                      nsldapi_free_request( ld, lr, 1 );
00329                      LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
00330                      LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN, NULL, NULL );
00331                      return( -1 ); /* connection dead */
00332               }
00333               LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
00334        }
00335 
00336        if ( timeout == NULL ) {
00337               tvp = NULL;
00338        } else {
00339               tv = *timeout;
00340               tvp = &tv;
00341               start_time = (long)time( NULL );
00342        }
00343 
00344        rc = -2;
00345        while ( rc == -2 ) {
00346 #ifdef LDAP_DEBUG
00347               if ( ldap_debug & LDAP_DEBUG_TRACE ) {
00348                      nsldapi_dump_connection( ld, ld->ld_conns, 1 );
00349                      nsldapi_dump_requests_and_responses( ld );
00350               }
00351 #endif /* LDAP_DEBUG */
00352               LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK );
00353               LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
00354               for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {
00355                      if ( lc->lconn_sb->sb_ber.ber_ptr <
00356                          lc->lconn_sb->sb_ber.ber_end ) {
00357                             rc = read1msg( ld, msgid, all, lc->lconn_sb,
00358                                 lc, result );
00359                             break;
00360                      }
00361               }
00362               LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
00363               LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
00364 
00365               if ( lc == NULL ) {
00366                      rc = nsldapi_iostatus_poll( ld, tvp );
00367 
00368 #if defined( LDAP_DEBUG ) && !defined( macintosh ) && !defined( DOS )
00369                      if ( rc == -1 ) {
00370                          LDAPDebug( LDAP_DEBUG_TRACE,
00371                                 "nsldapi_iostatus_poll returned -1: errno %d\n",
00372                                 LDAP_GET_ERRNO( ld ), 0, 0 );
00373                      }
00374 #endif
00375 
00376 #if !defined( macintosh ) && !defined( DOS )
00377                      if ( rc == 0 || ( rc == -1 && (( ld->ld_options &
00378                          LDAP_BITOPT_RESTART ) == 0 ||
00379                          LDAP_GET_ERRNO( ld ) != EINTR ))) {
00380 #else
00381                      if ( rc == -1 || rc == 0 ) {
00382 #endif
00383                             LDAP_SET_LDERRNO( ld, (rc == -1 ?
00384                                 LDAP_SERVER_DOWN : LDAP_TIMEOUT), NULL,
00385                                 NULL );
00386                             if ( rc == -1 ) {
00387                                    LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
00388                                    nsldapi_connection_lost_nolock( ld,
00389                                           NULL );
00390                                    LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
00391                             }
00392                             return( rc );
00393                      }
00394 
00395                      if ( rc == -1 ) {
00396                             rc = -2;      /* select interrupted: loop */
00397                      } else {
00398                             rc = -2;
00399                             LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK );
00400                             LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
00401                             for ( lc = ld->ld_conns; rc == -2 && lc != NULL;
00402                                 lc = nextlc ) {
00403                                    nextlc = lc->lconn_next;
00404                                    if ( lc->lconn_status ==
00405                                        LDAP_CONNST_CONNECTED &&
00406                                        nsldapi_iostatus_is_read_ready( ld,
00407                                        lc->lconn_sb )) {
00408                                           rc = read1msg( ld, msgid, all,
00409                                               lc->lconn_sb, lc, result );
00410                                    }
00411                                    else if (ld->ld_options & LDAP_BITOPT_ASYNC) {
00412                         if ( lr
00413                               && lc->lconn_status == LDAP_CONNST_CONNECTING
00414                               && nsldapi_iostatus_is_write_ready( ld,
00415                            lc->lconn_sb ) ) {
00416                             rc = nsldapi_ber_flush( ld, lc->lconn_sb, lr->lr_ber, 0, 1 );
00417                             if ( rc == 0 ) {
00418                                 rc = LDAP_RES_BIND;
00419                                 lc->lconn_status = LDAP_CONNST_CONNECTED;
00420                                 
00421                                 lr->lr_ber->ber_end = lr->lr_ber->ber_ptr;
00422                                 lr->lr_ber->ber_ptr = lr->lr_ber->ber_buf;
00423                                 nsldapi_iostatus_interest_read( ld, lc->lconn_sb );
00424                             }
00425                             else if ( rc == -1 ) {
00426                                 LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN, NULL, NULL );
00427                                 nsldapi_free_request( ld, lr, 0 );
00428                                 nsldapi_free_connection( ld, lc, NULL, NULL,
00429                                 0, 0 );
00430                             }
00431                         }
00432                         
00433                                    }
00434                             }
00435                             LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
00436                             LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
00437                      }
00438               }
00439 
00440               /*
00441                * It is possible that recursion occurred while chasing
00442                * referrals and as a result the message we are looking
00443                * for may have been placed on the response queue.  Look
00444                * for it there before continuing so we don't end up
00445                * waiting on the network for a message that we already
00446                * received!
00447                */
00448               if ( rc == -2 &&
00449                   check_response_queue( ld, msgid, all, 0, result ) != 0 ) {
00450                      LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, NULL );
00451                      rc = (*result)->lm_msgtype;
00452               }
00453 
00454               /*
00455                * honor the timeout if specified
00456                */
00457               if ( rc == -2 && tvp != NULL ) {
00458                      tmp_time = (long)time( NULL );
00459                      if (( tv.tv_sec -=  ( tmp_time - start_time )) <= 0 ) {
00460                             rc = 0;       /* timed out */
00461                             LDAP_SET_LDERRNO( ld, LDAP_TIMEOUT, NULL,
00462                                 NULL );
00463                             break;
00464                      }
00465 
00466                      LDAPDebug( LDAP_DEBUG_TRACE, "wait4msg:  %ld secs to go\n",
00467                             tv.tv_sec, 0, 0 );
00468                      start_time = tmp_time;
00469               }
00470        }
00471 
00472        return( rc );
00473 }
00474 
00475 
00476 /*
00477  * read1msg() should be called with LDAP_CONN_LOCK and LDAP_REQ_LOCK locked.
00478  */
00479 static int
00480 read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb, LDAPConn *lc,
00481     LDAPMessage **result )
00482 {
00483        BerElement    *ber;
00484        LDAPMessage   *new, *l, *prev, *chainprev, *tmp;
00485        long          id;
00486        unsigned long tag, len;
00487        int           terrno, lderr, foundit = 0;
00488        LDAPRequest   *lr;
00489        int           rc, has_parent, message_can_be_returned;
00490        int           manufactured_result = 0;
00491 
00492        LDAPDebug( LDAP_DEBUG_TRACE, "read1msg\n", 0, 0, 0 );
00493 
00494        message_can_be_returned = 1;       /* the usual case... */
00495 
00496        /*
00497         * if we are not already in the midst of reading a message, allocate
00498         * a ber that is associated with this connection
00499         */
00500        if ( lc->lconn_ber == NULLBER && nsldapi_alloc_ber_with_options( ld,
00501            &lc->lconn_ber ) != LDAP_SUCCESS ) {
00502               return( -1 );
00503        }
00504 
00505        /*
00506         * ber_get_next() doesn't set errno on EOF, so we pre-set it to
00507         * zero to avoid getting tricked by leftover "EAGAIN" errors
00508         */
00509        LDAP_SET_ERRNO( ld, 0 );
00510 
00511        /* get the next message */
00512        if ( (tag = ber_get_next( sb, &len, lc->lconn_ber ))
00513            != LDAP_TAG_MESSAGE ) {
00514               terrno = LDAP_GET_ERRNO( ld );
00515               if ( terrno == EWOULDBLOCK || terrno == EAGAIN ) {
00516                   return( -2 );    /* try again */
00517               }
00518               LDAP_SET_LDERRNO( ld, (tag == LBER_DEFAULT ? LDAP_SERVER_DOWN :
00519                     LDAP_LOCAL_ERROR), NULL, NULL );
00520               if ( tag == LBER_DEFAULT ) {
00521                      nsldapi_connection_lost_nolock( ld, sb );
00522               }
00523               return( -1 );
00524        }
00525 
00526        /*
00527         * Since we have received a complete message now, we pull this ber
00528         * out of the connection structure and never read into it again.
00529         */
00530        ber = lc->lconn_ber;
00531        lc->lconn_ber = NULLBER;
00532 
00533        /* message id */
00534        if ( ber_get_int( ber, &id ) == LBER_ERROR ) {
00535               LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
00536               return( -1 );
00537        }
00538 
00539        /* if it's been abandoned, toss it */
00540        if ( ldap_abandoned( ld, (int)id ) ) {
00541               ber_free( ber, 1 );
00542               return( -2 ); /* continue looking */
00543        }
00544 
00545        if ( id == LDAP_RES_UNSOLICITED ) {
00546               lr = NULL;
00547        } else if (( lr = nsldapi_find_request_by_msgid( ld, id )) == NULL ) {
00548               LDAPDebug( LDAP_DEBUG_ANY,
00549                   "no request for response with msgid %ld (tossing)\n",
00550                   id, 0, 0 );
00551               ber_free( ber, 1 );
00552               return( -2 ); /* continue looking */
00553        }
00554 
00555        /* the message type */
00556        if ( (tag = ber_peek_tag( ber, &len )) == LBER_ERROR ) {
00557               LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
00558               return( -1 );
00559        }
00560        LDAPDebug( LDAP_DEBUG_TRACE, "got %s msgid %ld, original id %d\n",
00561            ( tag == LDAP_RES_SEARCH_ENTRY ) ? "ENTRY" :
00562            ( tag == LDAP_RES_SEARCH_REFERENCE ) ? "REFERENCE" : "RESULT", id,
00563            ( lr == NULL ) ? id : lr->lr_origid );
00564 
00565        if ( lr != NULL ) {
00566               id = lr->lr_origid;
00567               lr->lr_res_msgtype = tag;
00568        }
00569        rc = -2;      /* default is to keep looking (no response found) */
00570 
00571        if ( id != LDAP_RES_UNSOLICITED && ( tag == LDAP_RES_SEARCH_REFERENCE ||
00572            tag != LDAP_RES_SEARCH_ENTRY )) {
00573               int           refchasing, reftotal, simple_request = 0;
00574 
00575               check_for_refs( ld, lr, ber, lc->lconn_version, &reftotal,
00576                   &refchasing );
00577 
00578               if ( refchasing > 0 || lr->lr_outrefcnt > 0 ) {
00579                      /*
00580                       * we're chasing one or more new refs...
00581                       */
00582                      ber_free( ber, 1 );
00583                      ber = NULLBER;
00584                      lr->lr_status = LDAP_REQST_CHASINGREFS;
00585                      message_can_be_returned = 0;
00586 
00587               } else if ( tag != LDAP_RES_SEARCH_REFERENCE ) {
00588                      /*
00589                       * this request is complete...
00590                       */
00591                      has_parent = ( lr->lr_parent != NULL );
00592 
00593                      if ( lr->lr_outrefcnt <= 0 && !has_parent ) {
00594                             /* request without any refs */
00595                             simple_request = ( reftotal == 0 );
00596                      }
00597 
00598                      /*
00599                       * If this is not a child request and it is a bind
00600                       * request, reset the connection's bind DN and
00601                       * status based on the result of the operation.
00602                       */
00603                      if ( !has_parent &&
00604                          LDAP_RES_BIND == lr->lr_res_msgtype &&
00605                          lr->lr_conn != NULL ) {
00606                             if ( lr->lr_conn->lconn_binddn != NULL ) {
00607                                    NSLDAPI_FREE(
00608                                        lr->lr_conn->lconn_binddn );
00609                             }
00610                             if ( LDAP_SUCCESS == nsldapi_parse_result( ld,
00611                                 lr->lr_res_msgtype, ber, &lderr, NULL,
00612                                 NULL, NULL, NULL )
00613                                 && LDAP_SUCCESS == lderr ) {
00614                                    lr->lr_conn->lconn_bound = 1;
00615                                    lr->lr_conn->lconn_binddn =
00616                                        lr->lr_binddn;
00617                                    lr->lr_binddn = NULL;
00618                             } else {
00619                                    lr->lr_conn->lconn_bound = 0;
00620                                    lr->lr_conn->lconn_binddn = NULL;
00621                             }
00622                      }
00623 
00624                      /*
00625                       * if this response is to a child request, we toss
00626                       * the message contents and just merge error info.
00627                       * into the parent.
00628                       */
00629                      if ( has_parent ) {
00630                             ber_free( ber, 1 );
00631                             ber = NULLBER;
00632                      }
00633                      while ( lr->lr_parent != NULL ) {
00634                             merge_error_info( ld, lr->lr_parent, lr );
00635 
00636                             lr = lr->lr_parent;
00637                             if ( --lr->lr_outrefcnt > 0 ) {
00638                                    break; /* not completely done yet */
00639                             }
00640                      }
00641 
00642                      /*
00643                       * we recognize a request as complete when:
00644                       *  1) it has no outstanding referrals
00645                       *  2) it is not a child request
00646                       *  3) we have received a result for the request (i.e.,
00647                       *     something other than an entry or a reference).
00648                       */
00649                      if ( lr->lr_outrefcnt <= 0 && lr->lr_parent == NULL &&
00650                          lr->lr_res_msgtype != LDAP_RES_SEARCH_ENTRY &&
00651                          lr->lr_res_msgtype != LDAP_RES_SEARCH_REFERENCE ) {
00652                             id = lr->lr_msgid;
00653                             tag = lr->lr_res_msgtype;
00654                             LDAPDebug( LDAP_DEBUG_TRACE,
00655                                 "request %ld done\n", id, 0, 0 );
00656 LDAPDebug( LDAP_DEBUG_TRACE,
00657 "res_errno: %d, res_error: <%s>, res_matched: <%s>\n",
00658 lr->lr_res_errno, lr->lr_res_error ? lr->lr_res_error : "",
00659 lr->lr_res_matched ? lr->lr_res_matched : "" );
00660                             if ( !simple_request ) {
00661                                    if ( ber != NULLBER ) {
00662                                           ber_free( ber, 1 );
00663                                           ber = NULLBER;
00664                                    }
00665                                    if ( build_result_ber( ld, &ber, lr )
00666                                        != LDAP_SUCCESS ) {
00667                                           rc = -1; /* fatal error */
00668                                    } else {
00669                                           manufactured_result = 1;
00670                                    }
00671                             }
00672 
00673                             nsldapi_free_request( ld, lr, 1 );
00674                      } else {
00675                             message_can_be_returned = 0;
00676                      }
00677               }
00678        }
00679 
00680        if ( ber == NULLBER ) {
00681               return( rc );
00682        }
00683 
00684        /* make a new ldap message */
00685        if ( (new = (LDAPMessage*)NSLDAPI_CALLOC( 1, sizeof(struct ldapmsg) ))
00686            == NULL ) {
00687               LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
00688               return( -1 );
00689        }
00690        new->lm_msgid = (int)id;
00691        new->lm_msgtype = tag;
00692        new->lm_ber = ber;
00693 
00694        /*
00695         * if this is a search entry or if this request is complete (i.e.,
00696         * there are no outstanding referrals) then add to cache and check
00697         * to see if we should return this to the caller right away or not.
00698         */
00699        if ( message_can_be_returned ) {
00700               if ( ld->ld_cache_on ) {
00701                      nsldapi_add_result_to_cache( ld, new );
00702               }
00703 
00704               if ( msgid == LDAP_RES_ANY || id == msgid ) {
00705                      if ( new->lm_msgtype == LDAP_RES_SEARCH_RESULT ) {
00706                             /*
00707                              * return the first response we have for this
00708                              * search request later (possibly an entire
00709                              * chain of messages).
00710                              */
00711                             foundit = 1;
00712                      } else if ( all == 0
00713                          || (new->lm_msgtype != LDAP_RES_SEARCH_REFERENCE
00714                          && new->lm_msgtype != LDAP_RES_SEARCH_ENTRY) ) {
00715                             *result = new;
00716                             LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL,
00717                                 NULL );
00718                             return( tag );
00719                      }
00720               }
00721        }
00722 
00723        /* 
00724         * if not, we must add it to the list of responses.  if
00725         * the msgid is already there, it must be part of an existing
00726         * search response.
00727         */
00728 
00729        prev = NULL;
00730        LDAP_MUTEX_LOCK( ld, LDAP_RESP_LOCK );
00731        for ( l = ld->ld_responses; l != NULL; l = l->lm_next ) {
00732               if ( l->lm_msgid == new->lm_msgid )
00733                      break;
00734               prev = l;
00735        }
00736 
00737        /* not part of an existing search response */
00738        if ( l == NULL ) {
00739               if ( foundit ) {
00740                      LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
00741                      *result = new;
00742                      LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, NULL );
00743                      return( tag );
00744               }
00745 
00746               new->lm_next = ld->ld_responses;
00747               ld->ld_responses = new;
00748               LDAPDebug( LDAP_DEBUG_TRACE,
00749                   "adding new response id %d type %d (looking for id %d)\n",
00750                   new->lm_msgid, new->lm_msgtype, msgid );
00751               LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
00752               if( message_can_be_returned )
00753                      POST( ld, new->lm_msgid, new );
00754               return( -2 ); /* continue looking */
00755        }
00756 
00757        LDAPDebug( LDAP_DEBUG_TRACE,
00758            "adding response id %d type %d (looking for id %d)\n",
00759            new->lm_msgid, new->lm_msgtype, msgid );
00760 
00761        /*
00762         * part of a search response - add to end of list of entries
00763         *
00764         * the first step is to find the end of the list of entries and
00765         * references.  after the following loop is executed, tmp points to
00766         * the last entry or reference in the chain.  If there are none,
00767         * tmp points to the search result.
00768         */
00769        chainprev = NULL;
00770        for ( tmp = l; tmp->lm_chain != NULL &&
00771            ( tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_ENTRY
00772            || tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_REFERENCE );
00773            tmp = tmp->lm_chain ) {
00774               chainprev = tmp;
00775        }
00776 
00777        /*
00778         * If this is a manufactured result message and a result is already
00779         * queued we throw away the one that is queued and replace it with
00780         * our new result.  This is necessary so we don't end up returning
00781         * more than one result.
00782         */
00783        if ( manufactured_result &&
00784            tmp->lm_msgtype == LDAP_RES_SEARCH_RESULT ) {
00785               /*
00786                * the result is the only thing in the chain... replace it.
00787                */
00788               new->lm_chain = tmp->lm_chain;
00789               new->lm_next = tmp->lm_next;
00790               if ( chainprev == NULL ) {
00791                      if ( prev == NULL ) {
00792                             ld->ld_responses = new;
00793                      } else {
00794                             prev->lm_next = new;
00795                      }
00796               } else {
00797                   chainprev->lm_chain = new;
00798               }
00799               if ( l == tmp ) {
00800                      l = new;
00801               }
00802               ldap_msgfree( tmp );
00803 
00804        } else if ( manufactured_result && tmp->lm_chain != NULL
00805            && tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_RESULT ) {
00806               /*
00807                * entries or references are also present, so the result
00808                * is the next entry after tmp.  replace it.
00809                */
00810               new->lm_chain = tmp->lm_chain->lm_chain;
00811               new->lm_next = tmp->lm_chain->lm_next;
00812               ldap_msgfree( tmp->lm_chain );
00813               tmp->lm_chain = new;
00814 
00815        } else if ( tmp->lm_msgtype == LDAP_RES_SEARCH_RESULT ) {
00816               /*
00817                * the result is the only thing in the chain... add before it.
00818                */
00819               new->lm_chain = tmp;
00820               if ( chainprev == NULL ) {
00821                      if ( prev == NULL ) {
00822                             ld->ld_responses = new;
00823                      } else {
00824                             prev->lm_next = new;
00825                      }
00826               } else {
00827                   chainprev->lm_chain = new;
00828               }
00829               if ( l == tmp ) {
00830                      l = new;
00831               }
00832 
00833        } else {
00834               /*
00835                * entries and/or references are present... add to the end
00836                * of the entry/reference part of the chain.
00837                */
00838               new->lm_chain = tmp->lm_chain;
00839               tmp->lm_chain = new;
00840        }
00841 
00842        /*
00843         * return the first response or the whole chain if that's what
00844         * we were looking for....
00845         */
00846        if ( foundit ) {
00847               if ( all == 0 && l->lm_chain != NULL ) {
00848                      /*
00849                       * only return the first response in the chain
00850                       */
00851                      if ( prev == NULL ) {
00852                             ld->ld_responses = l->lm_chain;
00853                      } else {
00854                             prev->lm_next = l->lm_chain;
00855                      }
00856                      l->lm_chain = NULL;
00857                      tag = l->lm_msgtype;
00858               } else {
00859                      /*
00860                       * return all of the responses (may be a chain)
00861                       */
00862                      if ( prev == NULL ) {
00863                             ld->ld_responses = l->lm_next;
00864                      } else {
00865                             prev->lm_next = l->lm_next;
00866                      }
00867               }
00868               *result = l;
00869               LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
00870               LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, NULL );
00871               return( tag );
00872        }
00873        LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
00874        return( -2 ); /* continue looking */
00875 }
00876 
00877 
00878 /*
00879  * check for LDAPv2+ (UMich extension) or LDAPv3 referrals or references
00880  * errors are merged in "lr".
00881  */
00882 static void
00883 check_for_refs( LDAP *ld, LDAPRequest *lr, BerElement *ber,
00884     int ldapversion, int *totalcountp, int *chasingcountp )
00885 {
00886        int           err, origerr;
00887        char          *errstr, *matcheddn, **v3refs;
00888 
00889        LDAPDebug( LDAP_DEBUG_TRACE, "check_for_refs\n", 0, 0, 0 );
00890 
00891        *chasingcountp = *totalcountp = 0;
00892 
00893        if ( ldapversion < LDAP_VERSION2 || ( lr->lr_parent == NULL
00894            && ( ld->ld_options & LDAP_BITOPT_REFERRALS ) == 0 )) {
00895               /* referrals are not supported or are disabled */
00896               return;
00897        }
00898 
00899        if ( lr->lr_res_msgtype == LDAP_RES_SEARCH_REFERENCE ) {
00900               err = nsldapi_parse_reference( ld, ber, &v3refs, NULL );
00901               origerr = LDAP_REFERRAL;    /* a small lie... */
00902               matcheddn = errstr = NULL;
00903        } else {
00904               err = nsldapi_parse_result( ld, lr->lr_res_msgtype, ber,
00905                   &origerr, &matcheddn, &errstr, &v3refs, NULL );
00906        }
00907 
00908        if ( err != LDAP_SUCCESS ) {
00909               /* parse failed */
00910               return;
00911        }
00912 
00913        if ( origerr == LDAP_REFERRAL ) {  /* ldapv3 */
00914               if ( v3refs != NULL ) {
00915                      err = nsldapi_chase_v3_refs( ld, lr, v3refs,
00916                          ( lr->lr_res_msgtype == LDAP_RES_SEARCH_REFERENCE ),
00917                          totalcountp, chasingcountp );
00918                      ldap_value_free( v3refs );
00919               }
00920        } else if ( ldapversion == LDAP_VERSION2
00921            && origerr != LDAP_SUCCESS ) {
00922               /* referrals may be present in the error string */
00923               err = nsldapi_chase_v2_referrals( ld, lr, &errstr,
00924                   totalcountp, chasingcountp );
00925        }
00926 
00927        /* set LDAP errno, message, and matched string appropriately */
00928        if ( lr->lr_res_error != NULL ) {
00929               NSLDAPI_FREE( lr->lr_res_error );
00930        }
00931        lr->lr_res_error = errstr;
00932 
00933        if ( lr->lr_res_matched != NULL ) {
00934               NSLDAPI_FREE( lr->lr_res_matched );
00935        }
00936        lr->lr_res_matched = matcheddn;
00937 
00938        if ( err == LDAP_SUCCESS && ( *chasingcountp == *totalcountp )) {
00939               if ( *totalcountp > 0 && ( origerr == LDAP_PARTIAL_RESULTS
00940                   || origerr == LDAP_REFERRAL )) {
00941                      /* substitute success for referral error codes */
00942                      lr->lr_res_errno = LDAP_SUCCESS;
00943               } else {
00944                      /* preserve existing non-referral error code */
00945                      lr->lr_res_errno = origerr;
00946               }
00947        } else if ( err != LDAP_SUCCESS ) {
00948               /* error occurred while trying to chase referrals */
00949               lr->lr_res_errno = err;
00950        } else {
00951               /* some referrals were not recognized */
00952               lr->lr_res_errno = ( ldapversion == LDAP_VERSION2 )
00953                   ? LDAP_PARTIAL_RESULTS : LDAP_REFERRAL;
00954        }
00955               
00956        LDAPDebug( LDAP_DEBUG_TRACE,
00957            "check_for_refs: new result: msgid %d, res_errno %d, ",
00958            lr->lr_msgid, lr->lr_res_errno, 0 );
00959        LDAPDebug( LDAP_DEBUG_TRACE, " res_error <%s>, res_matched <%s>\n",
00960            lr->lr_res_error ? lr->lr_res_error : "",
00961            lr->lr_res_matched ? lr->lr_res_matched : "", 0 );
00962        LDAPDebug( LDAP_DEBUG_TRACE,
00963            "check_for_refs: %d new refs(s); chasing %d of them\n",
00964            *totalcountp, *chasingcountp, 0 );
00965 }
00966 
00967 
00968 /* returns an LDAP error code and also sets it in LDAP * */
00969 static int
00970 build_result_ber( LDAP *ld, BerElement **berp, LDAPRequest *lr )
00971 {
00972        unsigned long len;
00973        long          along;
00974        BerElement    *ber;
00975        int           err;
00976 
00977        if (( err = nsldapi_alloc_ber_with_options( ld, &ber ))
00978            != LDAP_SUCCESS ) {
00979               return( err );
00980        }
00981        *berp = ber;
00982        if ( ber_printf( ber, "{it{ess}}", lr->lr_msgid,
00983            (long)lr->lr_res_msgtype, lr->lr_res_errno,
00984            lr->lr_res_matched ? lr->lr_res_matched : "",
00985            lr->lr_res_error ? lr->lr_res_error : "" ) == -1 ) {
00986               return( LDAP_ENCODING_ERROR );
00987        }
00988 
00989        ber_reset( ber, 1 );
00990        if ( ber_skip_tag( ber, &len ) == LBER_ERROR ||
00991            ber_get_int( ber, &along ) == LBER_ERROR ||
00992            ber_peek_tag( ber, &len ) == LBER_ERROR ) {
00993               return( LDAP_DECODING_ERROR );
00994        }
00995 
00996        return( LDAP_SUCCESS );
00997 }
00998 
00999 
01000 static void
01001 merge_error_info( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr )
01002 {
01003 /*
01004  * Merge error information in "lr" with "parentr" error code and string.
01005  */
01006        if ( lr->lr_res_errno == LDAP_PARTIAL_RESULTS ) {
01007               parentr->lr_res_errno = lr->lr_res_errno;
01008               if ( lr->lr_res_error != NULL ) {
01009                      (void)nsldapi_append_referral( ld, &parentr->lr_res_error,
01010                          lr->lr_res_error );
01011               }
01012        } else if ( lr->lr_res_errno != LDAP_SUCCESS &&
01013            parentr->lr_res_errno == LDAP_SUCCESS ) {
01014               parentr->lr_res_errno = lr->lr_res_errno;
01015               if ( parentr->lr_res_error != NULL ) {
01016                      NSLDAPI_FREE( parentr->lr_res_error );
01017               }
01018               parentr->lr_res_error = lr->lr_res_error;
01019               lr->lr_res_error = NULL;
01020               if ( NAME_ERROR( lr->lr_res_errno )) {
01021                      if ( parentr->lr_res_matched != NULL ) {
01022                             NSLDAPI_FREE( parentr->lr_res_matched );
01023                      }
01024                      parentr->lr_res_matched = lr->lr_res_matched;
01025                      lr->lr_res_matched = NULL;
01026               }
01027        }
01028 
01029        LDAPDebug( LDAP_DEBUG_TRACE, "merged parent (id %d) error info:  ",
01030            parentr->lr_msgid, 0, 0 );
01031        LDAPDebug( LDAP_DEBUG_TRACE, "result lderrno %d, error <%s>, matched <%s>\n",
01032            parentr->lr_res_errno, parentr->lr_res_error ?
01033            parentr->lr_res_error : "", parentr->lr_res_matched ?
01034            parentr->lr_res_matched : "" );
01035 }
01036 
01037 #if defined( CLDAP )
01038 #if !defined( macintosh ) && !defined( DOS ) && !defined( _WINDOWS ) && !defined(XP_OS2)
01039 /* XXXmcs: was revised to support extended I/O callbacks but never compiled! */
01040 static int
01041 cldap_select1( LDAP *ld, struct timeval *timeout )
01042 {
01043        int           rc;
01044        static int    tblsize = 0;
01045        NSLDAPIIOStatus      *iosp = ld->ld_iostatus;
01046 
01047        if ( tblsize == 0 ) {
01048 #ifdef USE_SYSCONF
01049               tblsize = sysconf( _SC_OPEN_MAX );
01050 #else /* USE_SYSCONF */
01051               tblsize = getdtablesize();
01052 #endif /* USE_SYSCONF */
01053        }
01054 
01055        if ( tblsize >= FD_SETSIZE ) {
01056               /*
01057                * clamp value so we don't overrun the fd_set structure
01058                */
01059               tblsize = FD_SETSIZE - 1;
01060        }
01061 
01062        if ( NSLDAPI_IOSTATUS_TYPE_OSNATIVE == iosp->ios_type ) {
01063               fd_set        readfds;
01064 
01065               FD_ZERO( &readfds );
01066               FD_SET( ld->ld_sbp->sb_sd, &readfds );
01067 
01068               /* XXXmcs: UNIX platforms should use poll() */
01069               rc = select( tblsize, &readfds, 0, 0, timeout ) );
01070 
01071        } else if ( NSLDAPI_IOSTATUS_TYPE_CALLBACK == iosp->ios_type ) {
01072               LDAP_X_PollFD pollfds[ 1 ];
01073 
01074               pollfds[0].lpoll_fd = ld->ld_sbp->sb_sd;
01075               pollfds[0].lpoll_arg = ld->ld_sbp->sb_arg;
01076               pollfds[0].lpoll_events = LDAP_X_POLLIN;
01077               pollfds[0].lpoll_revents = 0;
01078               rc = ld->ld_extpoll_fn( pollfds, 1, nsldapi_tv2ms( timeout ),
01079                   ld->ld_ext_session_arg );
01080        } else {
01081               LDAPDebug( LDAP_DEBUG_ANY,
01082                   "nsldapi_iostatus_poll: unknown I/O type %d\n",
01083               rc = 0; /* simulate a timeout (what else to do?) */
01084        }
01085 
01086        return( rc );
01087 }
01088 #endif /* !macintosh */
01089 
01090 
01091 #ifdef macintosh
01092 static int
01093 cldap_select1( LDAP *ld, struct timeval *timeout )
01094 {
01095        /* XXXmcs: needs to be revised to support I/O callbacks */
01096        return( tcpselect( ld->ld_sbp->sb_sd, timeout ));
01097 }
01098 #endif /* macintosh */
01099 
01100 
01101 #if (defined( DOS ) && defined( WINSOCK )) || defined( _WINDOWS ) || defined(XP_OS2)
01102 /* XXXmcs: needs to be revised to support extended I/O callbacks */
01103 static int
01104 cldap_select1( LDAP *ld, struct timeval *timeout )
01105 {
01106     fd_set          readfds;
01107     int             rc;
01108 
01109     FD_ZERO( &readfds );
01110     FD_SET( ld->ld_sbp->sb_sd, &readfds );
01111 
01112     if ( NSLDAPI_IO_TYPE_STANDARD == ld->ldiou_type &&
01113        NULL != ld->ld_select_fn ) {
01114            rc = ld->ld_select_fn( 1, &readfds, 0, 0, timeout );
01115     } else if ( NSLDAPI_IO_TYPE_EXTENDED == ld->ldiou_type &&
01116        NULL != ld->ld_extselect_fn ) {
01117            rc = ld->ld_extselect_fn( ld->ld_ext_session_arg, 1, &readfds, 0,
01118               0, timeout ) );
01119     } else {
01120            /* XXXmcs: UNIX platforms should use poll() */
01121            rc = select( 1, &readfds, 0, 0, timeout ) );
01122     }
01123 
01124     return( rc == SOCKET_ERROR ? -1 : rc );
01125 }
01126 #endif /* WINSOCK || _WINDOWS */
01127 #endif /* CLDAP */
01128 
01129 int
01130 LDAP_CALL
01131 ldap_msgfree( LDAPMessage *lm )
01132 {
01133        LDAPMessage   *next;
01134        int           type = 0;
01135 
01136        LDAPDebug( LDAP_DEBUG_TRACE, "ldap_msgfree\n", 0, 0, 0 );
01137 
01138        for ( ; lm != NULL; lm = next ) {
01139               next = lm->lm_chain;
01140               type = lm->lm_msgtype;
01141               ber_free( lm->lm_ber, 1 );
01142               NSLDAPI_FREE( (char *) lm );
01143        }
01144 
01145        return( type );
01146 }
01147 
01148 /*
01149  * ldap_msgdelete - delete a message.  It returns:
01150  *     0      if the entire message was deleted
01151  *     -1     if the message was not found, or only part of it was found
01152  */
01153 int
01154 ldap_msgdelete( LDAP *ld, int msgid )
01155 {
01156        LDAPMessage   *lm, *prev;
01157        int           msgtype;
01158 
01159        LDAPDebug( LDAP_DEBUG_TRACE, "ldap_msgdelete\n", 0, 0, 0 );
01160 
01161        if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
01162               return( -1 ); /* punt */
01163        }
01164 
01165        prev = NULL;
01166         LDAP_MUTEX_LOCK( ld, LDAP_RESP_LOCK );
01167        for ( lm = ld->ld_responses; lm != NULL; lm = lm->lm_next ) {
01168               if ( lm->lm_msgid == msgid )
01169                      break;
01170               prev = lm;
01171        }
01172 
01173        if ( lm == NULL )
01174        {
01175               LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
01176               return( -1 );
01177        }
01178 
01179        if ( prev == NULL )
01180               ld->ld_responses = lm->lm_next;
01181        else
01182               prev->lm_next = lm->lm_next;
01183         LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
01184 
01185        msgtype = ldap_msgfree( lm );
01186        if ( msgtype == LDAP_RES_SEARCH_ENTRY
01187            || msgtype == LDAP_RES_SEARCH_REFERENCE ) {
01188               return( -1 );
01189        }
01190 
01191        return( 0 );
01192 }
01193 
01194 
01195 /*
01196  * return 1 if message msgid is waiting to be abandoned, 0 otherwise
01197  */
01198 static int
01199 ldap_abandoned( LDAP *ld, int msgid )
01200 {
01201        int    i;
01202 
01203        LDAP_MUTEX_LOCK( ld, LDAP_ABANDON_LOCK );
01204        if ( ld->ld_abandoned == NULL )
01205        {
01206               LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
01207               return( 0 );
01208        }
01209 
01210        for ( i = 0; ld->ld_abandoned[i] != -1; i++ )
01211               if ( ld->ld_abandoned[i] == msgid )
01212               {
01213                      LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
01214                      return( 1 );
01215               }
01216 
01217        LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
01218        return( 0 );
01219 }
01220 
01221 
01222 static int
01223 ldap_mark_abandoned( LDAP *ld, int msgid )
01224 {
01225        int    i;
01226 
01227        LDAP_MUTEX_LOCK( ld, LDAP_ABANDON_LOCK );
01228        if ( ld->ld_abandoned == NULL )
01229        {
01230               LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
01231               return( -1 );
01232        }
01233 
01234        for ( i = 0; ld->ld_abandoned[i] != -1; i++ )
01235               if ( ld->ld_abandoned[i] == msgid )
01236                      break;
01237 
01238        if ( ld->ld_abandoned[i] == -1 )
01239        {
01240               LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
01241               return( -1 );
01242        }
01243 
01244        for ( ; ld->ld_abandoned[i] != -1; i++ ) {
01245               ld->ld_abandoned[i] = ld->ld_abandoned[i + 1];
01246        }
01247 
01248        LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK );
01249        return( 0 );
01250 }
01251 
01252 
01253 #ifdef CLDAP
01254 int
01255 cldap_getmsg( LDAP *ld, struct timeval *timeout, BerElement **ber )
01256 {
01257        int           rc;
01258        unsigned long tag, len;
01259 
01260        if ( ld->ld_sbp->sb_ber.ber_ptr >= ld->ld_sbp->sb_ber.ber_end ) {
01261               rc = cldap_select1( ld, timeout );
01262               if ( rc == -1 || rc == 0 ) {
01263                      LDAP_SET_LDERRNO( ld, (rc == -1 ? LDAP_SERVER_DOWN :
01264                          LDAP_TIMEOUT), NULL, NULL );
01265                      return( rc );
01266               }
01267        }
01268 
01269        /* get the next message */
01270        if ( (tag = ber_get_next( ld->ld_sbp, &len, ber ))
01271            != LDAP_TAG_MESSAGE ) {
01272               LDAP_SET_LDERRNO( ld, (tag == LBER_DEFAULT ? LDAP_SERVER_DOWN :
01273                   LDAP_LOCAL_ERROR), NULL, NULL );
01274               return( -1 );
01275        }
01276 
01277        return( tag );
01278 }
01279 #endif /* CLDAP */
01280 
01281 int
01282 nsldapi_post_result( LDAP *ld, int msgid, LDAPMessage *result )
01283 {
01284        LDAPPend      *lp;
01285 
01286        LDAPDebug( LDAP_DEBUG_TRACE,
01287            "nsldapi_post_result(ld=0x%x, msgid=%d, result=0x%x)\n",
01288            ld, msgid, result );
01289        LDAP_MUTEX_LOCK( ld, LDAP_PEND_LOCK );
01290        if( msgid == LDAP_RES_ANY ) {
01291               /*
01292                * Look for any pending request for which someone is waiting.
01293                */
01294               for( lp = ld->ld_pend; lp != NULL; lp = lp->lp_next )
01295               {
01296                      if ( lp->lp_sema != NULL ) {
01297                             break;
01298                      } 
01299               }
01300               /*
01301                * If we did't find a pending request, lp is NULL at this
01302                * point, and we will leave this function without doing
01303                * anything more -- which is exactly what we want to do.
01304                */
01305        }
01306        else
01307        {
01308               /*
01309                * Look for a pending request specific to this message id
01310                */
01311               for( lp = ld->ld_pend; lp != NULL; lp = lp->lp_next )
01312               {
01313                      if( lp->lp_msgid == msgid )
01314                             break;
01315               }
01316 
01317               if( lp == NULL )
01318               {
01319                      /*
01320                       * No pending requests for this response... append to
01321                       * our pending result list.
01322                       */
01323                      LDAPPend      *newlp;
01324                      newlp = (LDAPPend *)NSLDAPI_CALLOC( 1,
01325                          sizeof( LDAPPend ));
01326                      if( newlp == NULL )
01327                      {
01328                             LDAP_MUTEX_UNLOCK( ld, LDAP_PEND_LOCK );
01329                             LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL,
01330                                 NULL );
01331                             return (-1);
01332                      }
01333                      newlp->lp_msgid = msgid;
01334                      newlp->lp_result = result;
01335                      link_pend( ld, newlp );
01336               }
01337        }
01338 
01339 
01340        if( lp != NULL )
01341        {
01342               /*
01343                * Wake up a thread that is waiting for this result.
01344                */
01345               lp->lp_msgid = msgid;
01346               lp->lp_result = result;
01347               LDAP_SEMA_POST( ld, lp );
01348        }
01349 
01350        LDAP_MUTEX_UNLOCK( ld, LDAP_PEND_LOCK );
01351        return (0);
01352 }
01353 
01354 static void
01355 link_pend( LDAP *ld, LDAPPend *lp )
01356 {
01357        if (( lp->lp_next = ld->ld_pend ) != NULL )
01358        {
01359               lp->lp_next->lp_prev = lp;    
01360        } 
01361        ld->ld_pend = lp; 
01362        lp->lp_prev = NULL; 
01363 }
01364 
01365 #if 0 /* these functions are no longer used */
01366 static void
01367 unlink_pend( LDAP *ld, LDAPPend *lp )
01368 {
01369         if ( lp->lp_prev == NULL ) {
01370                 ld->ld_pend = lp->lp_next;
01371         } else { 
01372                 lp->lp_prev->lp_next = lp->lp_next;
01373         }
01374  
01375         if ( lp->lp_next != NULL ) {
01376                 lp->lp_next->lp_prev = lp->lp_prev;
01377         }
01378 }
01379 
01380 static int
01381 unlink_msg( LDAP *ld, int msgid, int all )
01382 {
01383        int rc;
01384        LDAPMessage   *lm, *lastlm, *nextlm;
01385 
01386        lastlm = NULL;
01387        LDAP_MUTEX_LOCK( ld, LDAP_RESP_LOCK );
01388        for ( lm = ld->ld_responses; lm != NULL; lm = nextlm )
01389        {
01390               nextlm = lm->lm_next;
01391 
01392               if ( lm->lm_msgid == msgid )
01393               {
01394                      LDAPMessage   *tmp;
01395 
01396                      if ( all == 0
01397                          || (lm->lm_msgtype != LDAP_RES_SEARCH_RESULT
01398                          && lm->lm_msgtype != LDAP_RES_SEARCH_REFERENCE
01399                          && lm->lm_msgtype != LDAP_RES_SEARCH_ENTRY) )
01400                             break;
01401 
01402                      for ( tmp = lm; tmp != NULL; tmp = tmp->lm_chain ) {
01403                             if ( tmp->lm_msgtype == LDAP_RES_SEARCH_RESULT )
01404                                    break;
01405                      }
01406                      if( tmp != NULL )
01407                             break;
01408               }
01409               lastlm = lm;
01410        }
01411 
01412        if( lm != NULL )
01413        {
01414 
01415               if ( all == 0 )
01416               {
01417                      if ( lm->lm_chain == NULL )
01418                      {
01419                             if ( lastlm == NULL )
01420                                    ld->ld_responses = lm->lm_next;
01421                             else
01422                                    lastlm->lm_next = lm->lm_next;
01423                      }
01424                      else
01425                      {
01426                             if ( lastlm == NULL )
01427                             {
01428                                    ld->ld_responses = lm->lm_chain;
01429                                    ld->ld_responses->lm_next = lm->lm_next;
01430                             }
01431                             else
01432                             {
01433                                    lastlm->lm_next = lm->lm_chain;
01434                                    lastlm->lm_next->lm_next = lm->lm_next;
01435                             }
01436                      }
01437               }
01438               else
01439               {
01440                      if ( lastlm == NULL )
01441                             ld->ld_responses = lm->lm_next;
01442                      else
01443                             lastlm->lm_next = lm->lm_next;
01444               }
01445 
01446               if ( all == 0 )
01447                      lm->lm_chain = NULL;
01448               lm->lm_next = NULL;
01449               rc = lm->lm_msgtype;
01450        }
01451        else
01452        {
01453               rc = -2;
01454        }
01455        LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
01456        return ( rc );
01457 }
01458 #endif /* 0 */