1 /* result.c - wait for an ldap result */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2007 The OpenLDAP Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
16 /* Portions Copyright (c) 1990 Regents of the University of Michigan.
17 * All rights reserved.
19 /* This notice applies to changes, created by or for Novell, Inc.,
20 * to preexisting works for which notices appear elsewhere in this file.
22 * Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved.
24 * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND TREATIES.
25 * USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO VERSION
26 * 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS AVAILABLE AT
27 * HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE" IN THE
28 * TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION OF THIS
29 * WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP PUBLIC
30 * LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT THE
31 * PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
33 * Modification to OpenLDAP source by Novell, Inc.
34 * April 2000 sfs Add code to process V3 referrals and search results
36 * Note: A verbatim copy of version 2.0.1 of the OpenLDAP Public License
37 * can be found in the file "build/LICENSE-2.0.1" in this distribution
38 * of OpenLDAP Software.
43 * LDAPResult ::= SEQUENCE {
44 * resultCode ENUMERATED { ... },
46 * diagnosticMessage LDAPString,
47 * referral [3] Referral OPTIONAL
49 * Referral ::= SEQUENCE OF LDAPURL (one or more)
50 * LDAPURL ::= LDAPString (limited to URL chars)
57 #include <ac/stdlib.h>
60 #include <ac/socket.h>
61 #include <ac/string.h>
63 #include <ac/unistd.h>
69 static int ldap_abandoned LDAP_P(( LDAP *ld, ber_int_t msgid, int *idx ));
70 static int ldap_mark_abandoned LDAP_P(( LDAP *ld, ber_int_t msgid, int idx ));
71 static int wait4msg LDAP_P(( LDAP *ld, ber_int_t msgid, int all, struct timeval *timeout,
72 LDAPMessage **result ));
73 static ber_tag_t try_read1msg LDAP_P(( LDAP *ld, ber_int_t msgid,
74 int all, LDAPConn **lc, LDAPMessage **result ));
75 static ber_tag_t build_result_ber LDAP_P(( LDAP *ld, BerElement **bp, LDAPRequest *lr ));
76 static void merge_error_info LDAP_P(( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr ));
77 static LDAPMessage * chkResponseList LDAP_P(( LDAP *ld, int msgid, int all));
79 #define LDAP_MSG_X_KEEP_LOOKING (-2)
83 * ldap_result - wait for an ldap result response to a message from the
84 * ldap server. If msgid is LDAP_RES_ANY (-1), any message will be
85 * accepted. If msgid is LDAP_RES_UNSOLICITED (0), any unsolicited
86 * message is accepted. Otherwise ldap_result will wait for a response
87 * with msgid. If all is LDAP_MSG_ONE (0) the first message with id
88 * msgid will be accepted, otherwise, ldap_result will wait for all
89 * responses with id msgid and then return a pointer to the entire list
90 * of messages. In general, this is only useful for search responses,
91 * which can be of three message types (zero or more entries, zero or
92 * search references, followed by an ldap result). An extension to
93 * LDAPv3 allows partial extended responses to be returned in response
94 * to any request. The type of the first message received is returned.
95 * When waiting, any messages that have been abandoned/discarded are
99 * ldap_result( s, msgid, all, timeout, result )
106 struct timeval *timeout,
107 LDAPMessage **result )
109 LDAPMessage *lm = NULL;
112 assert( ld != NULL );
113 assert( result != NULL );
115 Debug( LDAP_DEBUG_TRACE, "ldap_result ld %p msgid %d\n", (void *)ld, msgid, 0 );
117 #ifdef LDAP_R_COMPILE
118 ldap_pvt_thread_mutex_lock( &ld->ld_res_mutex );
122 /* this is already done inside wait4msg(), right?... */
123 lm = chkResponseList( ld, msgid, all );
127 rc = wait4msg( ld, msgid, all, timeout, result );
131 ld->ld_errno = LDAP_SUCCESS;
135 #ifdef LDAP_R_COMPILE
136 ldap_pvt_thread_mutex_unlock( &ld->ld_res_mutex );
148 LDAPMessage *lm, **lastlm, *nextlm;
152 * Look through the list of responses we have received on
153 * this association and see if the response we're interested in
154 * is there. If it is, return it. If not, call wait4msg() to
155 * wait until it arrives or timeout occurs.
158 #ifdef LDAP_R_COMPILE
159 LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex );
162 Debug( LDAP_DEBUG_TRACE,
163 "ldap_chkResponseList ld %p msgid %d all %d\n",
164 (void *)ld, msgid, all );
166 lastlm = &ld->ld_responses;
167 for ( lm = ld->ld_responses; lm != NULL; lm = nextlm ) {
170 nextlm = lm->lm_next;
173 if ( ldap_abandoned( ld, lm->lm_msgid, &idx ) ) {
174 Debug( LDAP_DEBUG_ANY,
175 "response list msg abandoned, "
176 "msgid %d message type %s\n",
177 lm->lm_msgid, ldap_int_msgtype2str( lm->lm_msgtype ), 0 );
179 switch ( lm->lm_msgtype ) {
180 case LDAP_RES_SEARCH_ENTRY:
181 case LDAP_RES_SEARCH_REFERENCE:
182 case LDAP_RES_INTERMEDIATE:
186 /* there's no need to keep the id
187 * in the abandoned list any longer */
188 ldap_mark_abandoned( ld, lm->lm_msgid, idx );
192 /* Remove this entry from list */
200 if ( msgid == LDAP_RES_ANY || lm->lm_msgid == msgid ) {
203 if ( all == LDAP_MSG_ONE ||
204 all == LDAP_MSG_RECEIVED ||
205 msgid == LDAP_RES_UNSOLICITED )
210 tmp = lm->lm_chain_tail;
211 if ( tmp->lm_msgtype == LDAP_RES_SEARCH_ENTRY ||
212 tmp->lm_msgtype == LDAP_RES_SEARCH_REFERENCE ||
213 tmp->lm_msgtype == LDAP_RES_INTERMEDIATE )
224 lastlm = &lm->lm_next;
228 /* Found an entry, remove it from the list */
229 if ( all == LDAP_MSG_ONE && lm->lm_chain != NULL ) {
230 *lastlm = lm->lm_chain;
231 lm->lm_chain->lm_next = lm->lm_next;
232 lm->lm_chain->lm_chain_tail = ( lm->lm_chain_tail != lm ) ? lm->lm_chain_tail : lm->lm_chain;
234 lm->lm_chain_tail = NULL;
236 *lastlm = lm->lm_next;
243 Debug( LDAP_DEBUG_TRACE,
244 "ldap_chkResponseList returns ld %p NULL\n", (void *)ld, 0, 0);
246 Debug( LDAP_DEBUG_TRACE,
247 "ldap_chkResponseList returns ld %p msgid %d, type 0x%02lu\n",
248 (void *)ld, lm->lm_msgid, (unsigned long)lm->lm_msgtype );
260 struct timeval *timeout,
261 LDAPMessage **result )
264 struct timeval tv = { 0 },
267 time_t start_time = 0;
271 assert( ld != NULL );
272 assert( result != NULL );
274 #ifdef LDAP_R_COMPILE
275 LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex );
278 if ( timeout == NULL ) {
279 timeout = ld->ld_options.ldo_tm_api;
283 if ( timeout == NULL ) {
284 Debug( LDAP_DEBUG_TRACE, "wait4msg ld %p msgid %d (infinite timeout)\n",
285 (void *)ld, msgid, 0 );
287 Debug( LDAP_DEBUG_TRACE, "wait4msg ld %p msgid %d (timeout %ld usec)\n",
288 (void *)ld, msgid, (long)timeout->tv_sec * 1000000 + timeout->tv_usec );
290 #endif /* LDAP_DEBUG */
292 if ( timeout == NULL ) {
298 start_time = time( NULL );
301 rc = LDAP_MSG_X_KEEP_LOOKING;
302 while ( rc == LDAP_MSG_X_KEEP_LOOKING ) {
304 if ( ldap_debug & LDAP_DEBUG_TRACE ) {
305 Debug( LDAP_DEBUG_TRACE, "wait4msg continue ld %p msgid %d all %d\n",
306 (void *)ld, msgid, all );
307 #ifdef LDAP_R_COMPILE
308 ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex );
310 ldap_dump_connection( ld, ld->ld_conns, 1 );
311 #ifdef LDAP_R_COMPILE
312 ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex );
313 ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
315 ldap_dump_requests_and_responses( ld );
316 #ifdef LDAP_R_COMPILE
317 ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
320 #endif /* LDAP_DEBUG */
322 if ( ( *result = chkResponseList( ld, msgid, all ) ) != NULL ) {
323 rc = (*result)->lm_msgtype;
328 #ifdef LDAP_R_COMPILE
329 ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex );
331 for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {
332 if ( ber_sockbuf_ctrl( lc->lconn_sb,
333 LBER_SB_OPT_DATA_READY, NULL ) )
335 #ifdef LDAP_R_COMPILE
336 ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex );
338 rc = try_read1msg( ld, msgid, all, &lc, result );
339 #ifdef LDAP_R_COMPILE
340 ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex );
346 #ifdef LDAP_R_COMPILE
347 ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex );
351 rc = ldap_int_select( ld, tvp );
354 Debug( LDAP_DEBUG_TRACE,
355 "ldap_int_select returned -1: errno %d\n",
356 sock_errno(), 0, 0 );
360 if ( rc == 0 || ( rc == -1 && (
361 !LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_RESTART)
362 || sock_errno() != EINTR ) ) )
364 ld->ld_errno = (rc == -1 ? LDAP_SERVER_DOWN :
370 rc = LDAP_MSG_X_KEEP_LOOKING; /* select interrupted: loop */
373 rc = LDAP_MSG_X_KEEP_LOOKING;
374 #ifdef LDAP_R_COMPILE
375 ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
377 if ( ld->ld_requests &&
378 ld->ld_requests->lr_status == LDAP_REQST_WRITING &&
379 ldap_is_write_ready( ld,
380 ld->ld_requests->lr_conn->lconn_sb ) )
382 ldap_int_flush_request( ld, ld->ld_requests );
384 #ifdef LDAP_R_COMPILE
385 ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
386 ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex );
388 for ( lc = ld->ld_conns;
389 rc == LDAP_MSG_X_KEEP_LOOKING && lc != NULL; )
391 if ( lc->lconn_status == LDAP_CONNST_CONNECTED &&
392 ldap_is_read_ready( ld, lc->lconn_sb ) )
394 #ifdef LDAP_R_COMPILE
395 ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex );
397 rc = try_read1msg( ld, msgid, all, &lc, result );
398 #ifdef LDAP_R_COMPILE
399 ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex );
402 /* if lc gets free()'d,
403 * there's no guarantee
404 * lc->lconn_next is still
405 * sane; better restart
409 /* don't get to next conn! */
417 #ifdef LDAP_R_COMPILE
418 ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex );
424 if ( rc == LDAP_MSG_X_KEEP_LOOKING && tvp != NULL ) {
425 tmp_time = time( NULL );
426 tv0.tv_sec -= ( tmp_time - start_time );
427 if ( tv0.tv_sec <= 0 ) {
428 rc = 0; /* timed out */
429 ld->ld_errno = LDAP_TIMEOUT;
432 tv.tv_sec = tv0.tv_sec;
434 Debug( LDAP_DEBUG_TRACE, "wait4msg ld %p %ld secs to go\n",
435 (void *)ld, (long) tv.tv_sec, 0 );
436 start_time = tmp_time;
450 LDAPMessage **result )
453 LDAPMessage *newmsg, *l, *prev;
459 LDAPRequest *lr, *tmplr, dummy_lr = { 0 };
462 int rc, refer_cnt, hadref, simple_request;
465 #ifdef LDAP_CONNECTIONLESS
466 LDAPMessage *tmp = NULL, *chain_head = NULL;
467 int moremsgs = 0, isv2 = 0;
470 assert( ld != NULL );
471 assert( lcp != NULL );
472 assert( *lcp != NULL );
474 #ifdef LDAP_R_COMPILE
475 LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex );
478 Debug( LDAP_DEBUG_TRACE, "read1msg: ld %p msgid %d all %d\n",
479 (void *)ld, msgid, all );
484 if ( lc->lconn_ber == NULL ) {
485 lc->lconn_ber = ldap_alloc_ber_with_options( ld );
487 if ( lc->lconn_ber == NULL ) {
493 assert( LBER_VALID (ber) );
495 /* get the next message */
497 #ifdef LDAP_CONNECTIONLESS
498 if ( LDAP_IS_UDP(ld) ) {
499 struct sockaddr from;
500 ber_int_sb_read( lc->lconn_sb, &from, sizeof(struct sockaddr) );
501 if ( ld->ld_options.ldo_version == LDAP_VERSION2 ) isv2 = 1;
505 tag = ber_get_next( lc->lconn_sb, &len, ber );
507 case LDAP_TAG_MESSAGE:
509 * We read a complete message.
510 * The connection should no longer need this ber.
512 lc->lconn_ber = NULL;
517 Debug( LDAP_DEBUG_CONNS,
518 "ber_get_next failed.\n", 0, 0, 0 );
521 if ( sock_errno() == EWOULDBLOCK ) return LDAP_MSG_X_KEEP_LOOKING;
524 if ( sock_errno() == EAGAIN ) return LDAP_MSG_X_KEEP_LOOKING;
526 ld->ld_errno = LDAP_SERVER_DOWN;
530 ld->ld_errno = LDAP_LOCAL_ERROR;
535 if ( ber_get_int( ber, &id ) == LBER_ERROR ) {
537 ld->ld_errno = LDAP_DECODING_ERROR;
541 /* id == 0 iff unsolicited notification message (RFC 4511) */
543 /* if it's been abandoned, toss it */
545 if ( ldap_abandoned( ld, id, &idx ) ) {
546 /* the message type */
547 tag = ber_peek_tag( ber, &len );
549 case LDAP_RES_SEARCH_ENTRY:
550 case LDAP_RES_SEARCH_REFERENCE:
551 case LDAP_RES_INTERMEDIATE:
556 /* there's no need to keep the id
557 * in the abandoned list any longer */
558 ldap_mark_abandoned( ld, id, idx );
562 Debug( LDAP_DEBUG_ANY,
563 "abandoned/discarded ld %p msgid %ld message type %s\n",
564 (void *)ld, (long)id, ldap_int_msgtype2str( tag ) );
568 if ( ber_sockbuf_ctrl( lc->lconn_sb, LBER_SB_OPT_DATA_READY, NULL ) ) {
571 return( LDAP_MSG_X_KEEP_LOOKING ); /* continue looking */
574 lr = ldap_find_request_by_msgid( ld, id );
576 const char *msg = "unknown";
578 /* the message type */
579 tag = ber_peek_tag( ber, &len );
585 msg = ldap_int_msgtype2str( tag );
589 Debug( LDAP_DEBUG_ANY,
590 "no request for response on ld %p msgid %ld message type %s (tossing)\n",
591 (void *)ld, (long)id, msg );
596 #ifdef LDAP_CONNECTIONLESS
597 if ( LDAP_IS_UDP(ld) && isv2 ) {
598 ber_scanf(ber, "x{");
604 /* the message type */
605 tag = ber_peek_tag( ber, &len );
606 if ( tag == LBER_ERROR ) {
607 ld->ld_errno = LDAP_DECODING_ERROR;
612 Debug( LDAP_DEBUG_TRACE,
613 "read1msg: ld %p msgid %ld message type %s\n",
614 (void *)ld, (long)lr->lr_msgid, ldap_int_msgtype2str( tag ) );
617 /* unsolicited notification message (RFC 4511) */
618 if ( tag != LDAP_RES_EXTENDED ) {
622 /* strictly speaking, it's an error; from RFC 4511:
624 4.4. Unsolicited Notification
626 An unsolicited notification is an LDAPMessage sent from the server to
627 the client that is not in response to any LDAPMessage received by the
628 server. It is used to signal an extraordinary condition in the
629 server or in the LDAP session between the client and the server. The
630 notification is of an advisory nature, and the server will not expect
631 any response to be returned from the client.
633 The unsolicited notification is structured as an LDAPMessage in which
634 the messageID is zero and protocolOp is set to the extendedResp
635 choice using the ExtendedResponse type (See Section 4.12). The
636 responseName field of the ExtendedResponse always contains an LDAPOID
637 that is unique for this notification.
639 * however, since unsolicited responses
640 * are of advisory nature, better
645 ld->ld_errno = LDAP_DECODING_ERROR;
656 hadref = simple_request = 0;
657 rc = LDAP_MSG_X_KEEP_LOOKING; /* default is to keep looking (no response found) */
658 lr->lr_res_msgtype = tag;
661 * Check for V3 search reference
663 if ( tag == LDAP_RES_SEARCH_REFERENCE ) {
664 if ( ld->ld_version > LDAP_VERSION2 ) {
665 /* This is a V3 search reference */
666 if ( LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_REFERRALS) ||
667 lr->lr_parent != NULL )
672 /* Get the referral list */
673 if ( ber_scanf( &tmpber, "{v}", &refs ) == LBER_ERROR ) {
674 rc = LDAP_DECODING_ERROR;
677 /* Note: refs array is freed by ldap_chase_v3referrals */
678 refer_cnt = ldap_chase_v3referrals( ld, lr, refs,
679 1, &lr->lr_res_error, &hadref );
680 if ( refer_cnt > 0 ) {
681 /* successfully chased reference */
682 /* If haven't got end search, set chasing referrals */
683 if ( lr->lr_status != LDAP_REQST_COMPLETED ) {
684 lr->lr_status = LDAP_REQST_CHASINGREFS;
685 Debug( LDAP_DEBUG_TRACE,
686 "read1msg: search ref chased, "
687 "mark request chasing refs, "
689 lr->lr_msgid, 0, 0 );
696 } else if ( tag != LDAP_RES_SEARCH_ENTRY && tag != LDAP_RES_INTERMEDIATE ) {
697 /* All results that just return a status, i.e. don't return data
698 * go through the following code. This code also chases V2 referrals
699 * and checks if all referrals have been chased.
701 char *lr_res_error = NULL;
703 tmpber = *ber; /* struct copy */
704 if ( ber_scanf( &tmpber, "{eAA", &lderr,
705 &lr->lr_res_matched, &lr_res_error )
708 if ( lr_res_error != NULL ) {
709 if ( lr->lr_res_error != NULL ) {
710 (void)ldap_append_referral( ld, &lr->lr_res_error, lr_res_error );
711 LDAP_FREE( (char *)lr_res_error );
714 lr->lr_res_error = lr_res_error;
719 /* Do we need to check for referrals? */
720 if ( LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_REFERRALS) ||
721 lr->lr_parent != NULL )
726 /* Check if V3 referral */
727 if ( ber_peek_tag( &tmpber, &len ) == LDAP_TAG_REFERRAL ) {
728 if ( ld->ld_version > LDAP_VERSION2 ) {
729 /* Get the referral list */
730 if ( ber_scanf( &tmpber, "{v}", &refs) == LBER_ERROR) {
731 rc = LDAP_DECODING_ERROR;
732 lr->lr_status = LDAP_REQST_COMPLETED;
733 Debug( LDAP_DEBUG_TRACE,
734 "read1msg: referral decode error, "
735 "mark request completed, ld %p msgid %d\n",
736 (void *)ld, lr->lr_msgid, 0 );
739 /* Chase the referral
740 * refs array is freed by ldap_chase_v3referrals
742 refer_cnt = ldap_chase_v3referrals( ld, lr, refs,
743 0, &lr->lr_res_error, &hadref );
744 lr->lr_status = LDAP_REQST_COMPLETED;
745 Debug( LDAP_DEBUG_TRACE,
746 "read1msg: referral %s chased, "
747 "mark request completed, ld %p msgid %d\n",
748 refer_cnt > 0 ? "" : "not",
749 (void *)ld, lr->lr_msgid);
750 if ( refer_cnt < 0 ) {
758 case LDAP_COMPARE_TRUE:
759 case LDAP_COMPARE_FALSE:
763 if ( lr->lr_res_error == NULL ) {
767 /* pedantic, should never happen */
768 if ( lr->lr_res_error[ 0 ] == '\0' ) {
769 LDAP_FREE( lr->lr_res_error );
770 lr->lr_res_error = NULL;
774 /* V2 referrals are in error string */
775 refer_cnt = ldap_chase_referrals( ld, lr,
776 &lr->lr_res_error, -1, &hadref );
777 lr->lr_status = LDAP_REQST_COMPLETED;
778 Debug( LDAP_DEBUG_TRACE,
779 "read1msg: V2 referral chased, "
780 "mark request completed, id = %d\n",
781 lr->lr_msgid, 0, 0 );
787 /* save errno, message, and matched string */
788 if ( !hadref || lr->lr_res_error == NULL ) {
790 lderr == LDAP_PARTIAL_RESULTS
791 ? LDAP_SUCCESS : lderr;
793 } else if ( ld->ld_errno != LDAP_SUCCESS ) {
794 lr->lr_res_errno = ld->ld_errno;
797 lr->lr_res_errno = LDAP_PARTIAL_RESULTS;
801 /* in any case, don't leave any lr_res_error 'round */
802 if ( lr_res_error ) {
803 LDAP_FREE( lr_res_error );
806 Debug( LDAP_DEBUG_TRACE,
807 "read1msg: ld %p %d new referrals\n",
808 (void *)ld, refer_cnt, 0 );
810 if ( refer_cnt != 0 ) { /* chasing referrals */
813 if ( refer_cnt < 0 ) {
814 ldap_return_request( ld, lr, 0 );
815 return( -1 ); /* fatal error */
817 lr->lr_res_errno = LDAP_SUCCESS; /* sucessfully chased referral */
820 if ( lr->lr_outrefcnt <= 0 && lr->lr_parent == NULL ) {
821 /* request without any referrals */
822 simple_request = ( hadref ? 0 : 1 );
825 /* request with referrals or child request */
830 lr->lr_status = LDAP_REQST_COMPLETED; /* declare this request done */
831 Debug( LDAP_DEBUG_TRACE,
832 "read1msg: mark request completed, ld %p msgid %d\n",
833 (void *)ld, lr->lr_msgid, 0);
834 while ( lr->lr_parent != NULL ) {
835 merge_error_info( ld, lr->lr_parent, lr );
838 if ( --lr->lr_outrefcnt > 0 ) {
839 break; /* not completely done yet */
843 /* Check if all requests are finished, lr is now parent */
845 if ( tmplr->lr_status == LDAP_REQST_COMPLETED ) {
846 for ( tmplr = lr->lr_child;
848 tmplr = tmplr->lr_refnext )
850 if ( tmplr->lr_status != LDAP_REQST_COMPLETED ) break;
854 /* This is the parent request if the request has referrals */
855 if ( lr->lr_outrefcnt <= 0 &&
856 lr->lr_parent == NULL &&
860 tag = lr->lr_res_msgtype;
861 Debug( LDAP_DEBUG_ANY, "request done: ld %p msgid %ld\n",
862 (void *)ld, (long) id, 0 );
863 Debug( LDAP_DEBUG_TRACE,
864 "res_errno: %d, res_error: <%s>, "
865 "res_matched: <%s>\n",
867 lr->lr_res_error ? lr->lr_res_error : "",
868 lr->lr_res_matched ? lr->lr_res_matched : "" );
869 if ( !simple_request ) {
872 if ( build_result_ber( ld, &ber, lr )
875 rc = -1; /* fatal error */
879 if ( lr != &dummy_lr ) {
880 ldap_return_request( ld, lr, 1 );
886 * RF 4511 unsolicited (id == 0) responses
887 * shouldn't necessarily end the connection
889 if ( lc != NULL && id != 0 ) {
890 #ifdef LDAP_R_COMPILE
891 ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
893 ldap_free_connection( ld, lc, 0, 1 );
894 #ifdef LDAP_R_COMPILE
895 ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
903 if ( lr != &dummy_lr ) {
904 ldap_return_request( ld, lr, 0 );
913 /* try to handle unsolicited responses as appropriate */
914 if ( id == 0 && msgid > LDAP_RES_UNSOLICITED ) {
917 tag = ber_peek_tag( &tmpber, &len );
919 /* we have a res oid */
920 if ( tag == LDAP_TAG_EXOP_RES_OID ) {
921 static struct berval bv_nod = BER_BVC( LDAP_NOTICE_OF_DISCONNECTION );
922 struct berval resoid = BER_BVNULL;
924 if ( ber_scanf( &tmpber, "m", &resoid ) == LBER_ERROR ) {
925 ld->ld_errno = LDAP_DECODING_ERROR;
930 assert( !BER_BVISEMPTY( &resoid ) );
932 is_nod = ber_bvcmp( &resoid, &bv_nod ) == 0;
934 tag = ber_peek_tag( &tmpber, &len );
937 #if 0 /* don't need right now */
938 /* we have res data */
939 if ( tag == LDAP_TAG_EXOP_RES_VALUE ) {
940 struct berval resdata;
942 if ( ber_scanf( &tmpber, "m", &resdata ) == LBER_ERROR ) {
943 ld->ld_errno = LDAP_DECODING_ERROR;
952 /* handle RFC 4511 "Notice of Disconnection" locally */
955 if ( tag == LDAP_TAG_EXOP_RES_VALUE ) {
956 ld->ld_errno = LDAP_DECODING_ERROR;
961 /* get rid of the connection... */
963 #ifdef LDAP_R_COMPILE
964 ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
966 ldap_free_connection( ld, lc, 0, 1 );
967 #ifdef LDAP_R_COMPILE
968 ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
973 /* need to return -1, because otherwise
974 * a valid result is expected */
979 /* make a new ldap message */
980 newmsg = (LDAPMessage *) LDAP_CALLOC( 1, sizeof(LDAPMessage) );
981 if ( newmsg == NULL ) {
982 ld->ld_errno = LDAP_NO_MEMORY;
985 newmsg->lm_msgid = (int)id;
986 newmsg->lm_msgtype = tag;
987 newmsg->lm_ber = ber;
988 newmsg->lm_chain_tail = newmsg;
990 #ifdef LDAP_CONNECTIONLESS
991 /* CLDAP replies all fit in a single datagram. In LDAPv2 RFC1798
992 * the responses are all a sequence wrapped in one message. In
993 * LDAPv3 each response is in its own message. The datagram must
994 * end with a SearchResult. We can't just parse each response in
995 * separate calls to try_read1msg because the header info is only
996 * present at the beginning of the datagram, not at the beginning
997 * of each response. So parse all the responses at once and queue
998 * them up, then pull off the first response to return to the
999 * caller when all parsing is complete.
1001 if ( LDAP_IS_UDP(ld) ) {
1002 /* If not a result, look for more */
1003 if ( tag != LDAP_RES_SEARCH_RESULT ) {
1007 /* LDAPv2: dup the current ber, skip past the current
1008 * response, and see if there are any more after it.
1010 ber = ber_dup( ber );
1011 ber_scanf( ber, "x" );
1012 if ( ber_peek_tag( ber, &len ) != LBER_DEFAULT ) {
1013 /* There's more - dup the ber buffer so they can all be
1014 * individually freed by ldap_msgfree.
1017 ber_get_option( ber, LBER_OPT_BER_REMAINING_BYTES, &len );
1018 bv.bv_val = LDAP_MALLOC( len );
1021 ber_read( ber, bv.bv_val, len );
1023 ber_init2( ber, &bv, ld->ld_lberoptions );
1027 /* LDAPv3: Just allocate a new ber. Since this is a buffered
1028 * datagram, if the sockbuf is readable we still have data
1031 ber = ldap_alloc_ber_with_options( ld );
1032 if ( ber_sockbuf_ctrl( lc->lconn_sb, LBER_SB_OPT_DATA_READY, NULL ) ) ok = 1;
1034 /* set up response chain */
1035 if ( tmp == NULL ) {
1036 newmsg->lm_next = ld->ld_responses;
1037 ld->ld_responses = newmsg;
1038 chain_head = newmsg;
1040 tmp->lm_chain = newmsg;
1042 chain_head->lm_chain_tail = newmsg;
1044 /* "ok" means there's more to parse */
1053 /* got to end of datagram without a SearchResult. Free
1054 * our dup'd ber, but leave any buffer alone. For v2 case,
1055 * the previous response is still using this buffer. For v3,
1056 * the new ber has no buffer to free yet.
1061 } else if ( moremsgs ) {
1062 /* got search result, and we had multiple responses in 1 datagram.
1063 * stick the result onto the end of the chain, and then pull the
1064 * first response off the head of the chain.
1066 tmp->lm_chain = newmsg;
1067 chain_head->lm_chain_tail = newmsg;
1068 *result = chkResponseList( ld, msgid, all );
1069 ld->ld_errno = LDAP_SUCCESS;
1070 return( (*result)->lm_msgtype );
1073 #endif /* LDAP_CONNECTIONLESS */
1075 /* is this the one we're looking for? */
1076 if ( msgid == LDAP_RES_ANY || id == msgid ) {
1077 if ( all == LDAP_MSG_ONE
1078 || ( newmsg->lm_msgtype != LDAP_RES_SEARCH_RESULT
1079 && newmsg->lm_msgtype != LDAP_RES_SEARCH_ENTRY
1080 && newmsg->lm_msgtype != LDAP_RES_SEARCH_REFERENCE ) )
1083 ld->ld_errno = LDAP_SUCCESS;
1086 } else if ( newmsg->lm_msgtype == LDAP_RES_SEARCH_RESULT) {
1087 foundit = 1; /* return the chain later */
1092 * if not, we must add it to the list of responses. if
1093 * the msgid is already there, it must be part of an existing
1098 for ( l = ld->ld_responses; l != NULL; l = l->lm_next ) {
1099 if ( l->lm_msgid == newmsg->lm_msgid ) {
1105 /* not part of an existing search response */
1112 newmsg->lm_next = ld->ld_responses;
1113 ld->ld_responses = newmsg;
1117 Debug( LDAP_DEBUG_TRACE, "adding response ld %p msgid %ld type %ld:\n",
1118 (void *)ld, (long) newmsg->lm_msgid, (long) newmsg->lm_msgtype );
1120 /* part of a search response - add to end of list of entries */
1121 l->lm_chain_tail->lm_chain = newmsg;
1122 l->lm_chain_tail = newmsg;
1124 /* return the whole chain if that's what we were looking for */
1126 if ( prev == NULL ) {
1127 ld->ld_responses = l->lm_next;
1129 prev->lm_next = l->lm_next;
1136 ld->ld_errno = LDAP_SUCCESS;
1139 if ( lc && ber_sockbuf_ctrl( lc->lconn_sb, LBER_SB_OPT_DATA_READY, NULL ) ) {
1142 return( LDAP_MSG_X_KEEP_LOOKING ); /* continue looking */
1147 build_result_ber( LDAP *ld, BerElement **bp, LDAPRequest *lr )
1155 ber = ldap_alloc_ber_with_options( ld );
1158 ld->ld_errno = LDAP_NO_MEMORY;
1162 if ( ber_printf( ber, "{it{ess}}", lr->lr_msgid,
1163 lr->lr_res_msgtype, lr->lr_res_errno,
1164 lr->lr_res_matched ? lr->lr_res_matched : "",
1165 lr->lr_res_error ? lr->lr_res_error : "" ) == -1 )
1167 ld->ld_errno = LDAP_ENCODING_ERROR;
1169 return( LBER_ERROR );
1172 ber_reset( ber, 1 );
1174 if ( ber_skip_tag( ber, &len ) == LBER_ERROR ) {
1175 ld->ld_errno = LDAP_DECODING_ERROR;
1177 return( LBER_ERROR );
1180 if ( ber_get_enum( ber, &along ) == LBER_ERROR ) {
1181 ld->ld_errno = LDAP_DECODING_ERROR;
1183 return( LBER_ERROR );
1186 tag = ber_peek_tag( ber, &len );
1188 if ( tag == LBER_ERROR ) {
1189 ld->ld_errno = LDAP_DECODING_ERROR;
1191 return( LBER_ERROR );
1200 * Merge error information in "lr" with "parentr" error code and string.
1203 merge_error_info( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr )
1205 if ( lr->lr_res_errno == LDAP_PARTIAL_RESULTS ) {
1206 parentr->lr_res_errno = lr->lr_res_errno;
1207 if ( lr->lr_res_error != NULL ) {
1208 (void)ldap_append_referral( ld, &parentr->lr_res_error,
1212 } else if ( lr->lr_res_errno != LDAP_SUCCESS &&
1213 parentr->lr_res_errno == LDAP_SUCCESS )
1215 parentr->lr_res_errno = lr->lr_res_errno;
1216 if ( parentr->lr_res_error != NULL ) {
1217 LDAP_FREE( parentr->lr_res_error );
1219 parentr->lr_res_error = lr->lr_res_error;
1220 lr->lr_res_error = NULL;
1221 if ( LDAP_NAME_ERROR( lr->lr_res_errno ) ) {
1222 if ( parentr->lr_res_matched != NULL ) {
1223 LDAP_FREE( parentr->lr_res_matched );
1225 parentr->lr_res_matched = lr->lr_res_matched;
1226 lr->lr_res_matched = NULL;
1230 Debug( LDAP_DEBUG_TRACE, "merged parent (id %d) error info: ",
1231 parentr->lr_msgid, 0, 0 );
1232 Debug( LDAP_DEBUG_TRACE, "result errno %d, error <%s>, matched <%s>\n",
1233 parentr->lr_res_errno,
1234 parentr->lr_res_error ? parentr->lr_res_error : "",
1235 parentr->lr_res_matched ? parentr->lr_res_matched : "" );
1241 ldap_msgtype( LDAPMessage *lm )
1243 assert( lm != NULL );
1244 return ( lm != NULL ) ? (int)lm->lm_msgtype : -1;
1249 ldap_msgid( LDAPMessage *lm )
1251 assert( lm != NULL );
1253 return ( lm != NULL ) ? lm->lm_msgid : -1;
1258 ldap_int_msgtype2str( ber_tag_t tag )
1261 case LDAP_RES_ADD: return "add";
1262 case LDAP_RES_BIND: return "bind";
1263 case LDAP_RES_COMPARE: return "compare";
1264 case LDAP_RES_DELETE: return "delete";
1265 case LDAP_RES_EXTENDED: return "extended-result";
1266 case LDAP_RES_INTERMEDIATE: return "intermediate";
1267 case LDAP_RES_MODIFY: return "modify";
1268 case LDAP_RES_RENAME: return "rename";
1269 case LDAP_RES_SEARCH_ENTRY: return "search-entry";
1270 case LDAP_RES_SEARCH_REFERENCE: return "search-reference";
1271 case LDAP_RES_SEARCH_RESULT: return "search-result";
1277 ldap_msgfree( LDAPMessage *lm )
1282 Debug( LDAP_DEBUG_TRACE, "ldap_msgfree\n", 0, 0, 0 );
1284 for ( ; lm != NULL; lm = next ) {
1285 next = lm->lm_chain;
1286 type = lm->lm_msgtype;
1287 ber_free( lm->lm_ber, 1 );
1288 LDAP_FREE( (char *) lm );
1295 * ldap_msgdelete - delete a message. It returns:
1296 * 0 if the entire message was deleted
1297 * -1 if the message was not found, or only part of it was found
1300 ldap_msgdelete( LDAP *ld, int msgid )
1302 LDAPMessage *lm, *prev;
1305 assert( ld != NULL );
1307 Debug( LDAP_DEBUG_TRACE, "ldap_msgdelete ld=%p msgid=%d\n",
1308 (void *)ld, msgid, 0 );
1310 #ifdef LDAP_R_COMPILE
1311 ldap_pvt_thread_mutex_lock( &ld->ld_res_mutex );
1314 for ( lm = ld->ld_responses; lm != NULL; lm = lm->lm_next ) {
1315 if ( lm->lm_msgid == msgid ) {
1325 if ( prev == NULL ) {
1326 ld->ld_responses = lm->lm_next;
1328 prev->lm_next = lm->lm_next;
1331 #ifdef LDAP_R_COMPILE
1332 ldap_pvt_thread_mutex_unlock( &ld->ld_res_mutex );
1335 switch ( ldap_msgfree( lm ) ) {
1336 case LDAP_RES_SEARCH_ENTRY:
1337 case LDAP_RES_SEARCH_REFERENCE:
1338 case LDAP_RES_INTERMEDIATE:
1354 * return the location of the message id in the array of abandoned
1355 * message ids, or -1
1357 * expects ld_res_mutex to be locked
1360 ldap_abandoned( LDAP *ld, ber_int_t msgid, int *idxp )
1362 #ifdef LDAP_R_COMPILE
1363 LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex );
1366 assert( idxp != NULL );
1367 assert( msgid >= 0 );
1368 assert( ld->ld_nabandoned >= 0 );
1370 return ldap_int_bisect_find( ld->ld_abandoned, ld->ld_nabandoned, msgid, idxp );
1374 * ldap_mark_abandoned
1376 * expects ld_res_mutex to be locked
1379 ldap_mark_abandoned( LDAP *ld, ber_int_t msgid, int idx )
1381 #ifdef LDAP_R_COMPILE
1382 LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex );
1385 /* NOTE: those assertions are repeated in ldap_int_bisect_delete() */
1387 assert( idx < ld->ld_nabandoned );
1388 assert( ld->ld_abandoned[ idx ] == msgid );
1390 return ldap_int_bisect_delete( &ld->ld_abandoned, &ld->ld_nabandoned,