* can be found in the file "build/LICENSE-2.0.1" in this distribution
* of OpenLDAP Software.
*/
-/* Portions Copyright (C) The Internet Society (1997)
- * ASN.1 fragments are from RFC 2251; see RFC for full legal notices.
- */
/*
- * LDAPv3 (RFC2251)
+ * LDAPv3 (RFC 4511)
* LDAPResult ::= SEQUENCE {
- * resultCode ENUMERATED { ... },
- * matchedDN LDAPDN,
- * errorMessage LDAPString,
- * referral Referral OPTIONAL
+ * resultCode ENUMERATED { ... },
+ * matchedDN LDAPDN,
+ * diagnosticMessage LDAPString,
+ * referral [3] Referral OPTIONAL
* }
* Referral ::= SEQUENCE OF LDAPURL (one or more)
* LDAPURL ::= LDAPString (limited to URL chars)
#include "ldap-int.h"
#include "ldap_log.h"
-static int ldap_abandoned LDAP_P(( LDAP *ld, ber_int_t msgid ));
+static int ldap_abandoned_idx LDAP_P(( LDAP *ld, ber_int_t msgid ));
+#define ldap_abandoned(ld, msgid) ( ldap_abandoned_idx((ld), (msgid)) > -1 )
static int ldap_mark_abandoned LDAP_P(( LDAP *ld, ber_int_t msgid ));
static int wait4msg LDAP_P(( LDAP *ld, ber_int_t msgid, int all, struct timeval *timeout,
LDAPMessage **result ));
struct timeval *timeout,
LDAPMessage **result )
{
- LDAPMessage *lm;
- int rc;
+ LDAPMessage *lm = NULL;
+ int rc;
assert( ld != NULL );
assert( result != NULL );
#ifdef LDAP_R_COMPILE
ldap_pvt_thread_mutex_lock( &ld->ld_res_mutex );
#endif
- lm = chkResponseList(ld, msgid, all);
+
+#if 0
+ /* this is already done inside wait4msg(), right?... */
+ lm = chkResponseList( ld, msgid, all );
+#endif
if ( lm == NULL ) {
rc = wait4msg( ld, msgid, all, timeout, result );
+
} else {
*result = lm;
ld->ld_errno = LDAP_SUCCESS;
rc = lm->lm_msgtype;
}
+
#ifdef LDAP_R_COMPILE
ldap_pvt_thread_mutex_unlock( &ld->ld_res_mutex );
#endif
- return( rc );
+
+ return rc;
}
static LDAPMessage *
int all)
{
LDAPMessage *lm, **lastlm, *nextlm;
+ int cnt = 0;
/*
* Look through the list of responses we have received on
lastlm = &ld->ld_responses;
for ( lm = ld->ld_responses; lm != NULL; lm = nextlm ) {
nextlm = lm->lm_next;
+ ++cnt;
if ( ldap_abandoned( ld, lm->lm_msgid ) ) {
Debug( LDAP_DEBUG_TRACE,
"ldap_chkResponseList msg abandoned, msgid %d\n",
- msgid, 0, 0 );
+ msgid, 0, 0 );
ldap_mark_abandoned( ld, lm->lm_msgid );
/* Remove this entry from list */
LDAPMessage *tmp;
if ( all == LDAP_MSG_ONE || all == LDAP_MSG_RECEIVED ||
- msgid == LDAP_RES_UNSOLICITED ) {
+ msgid == LDAP_RES_UNSOLICITED )
+ {
break;
}
tmp = lm->lm_chain_tail;
- if ((tmp->lm_msgtype == LDAP_RES_SEARCH_ENTRY) ||
+ if ( (tmp->lm_msgtype == LDAP_RES_SEARCH_ENTRY) ||
(tmp->lm_msgtype == LDAP_RES_SEARCH_REFERENCE) ||
- (tmp->lm_msgtype == LDAP_RES_INTERMEDIATE)) {
+ (tmp->lm_msgtype == LDAP_RES_INTERMEDIATE) )
+ {
tmp = NULL;
}
lastlm = &lm->lm_next;
}
- if ( lm != NULL ) {
+#if 0
+ {
+ char buf[ BUFSIZ ];
+
+ snprintf( buf, sizeof( buf ), "ld=%p msgid=%d%s cnt=%d",
+ ld, msgid, all ? " all" : "", cnt );
+ Debug( LDAP_DEBUG_TRACE, "+++ chkResponseList %s\n", buf, 0, 0 );
+ }
+#endif
+
+ if ( lm != NULL ) {
/* Found an entry, remove it from the list */
- if ( all == LDAP_MSG_ONE && lm->lm_chain != NULL ) {
+ 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 {
+ } else {
*lastlm = lm->lm_next;
}
- lm->lm_next = NULL;
- }
+ lm->lm_next = NULL;
+ }
#ifdef LDAP_DEBUG
- if( lm == NULL) {
+ if ( lm == NULL) {
Debug( LDAP_DEBUG_TRACE,
"ldap_chkResponseList returns ld %p NULL\n", (void *)ld, 0, 0);
} else {
Debug( LDAP_DEBUG_TRACE,
"ldap_chkResponseList returns ld %p msgid %d, type 0x%02lu\n",
- (void *)ld, lm->lm_msgid, (unsigned long) lm->lm_msgtype);
+ (void *)ld, lm->lm_msgid, (unsigned long) lm->lm_msgtype );
}
#endif
return lm;
*tvp;
time_t start_time = 0;
time_t tmp_time;
- LDAPConn *lc, *nextlc;
+ LDAPConn *lc;
assert( ld != NULL );
assert( result != NULL );
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 );
+#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 );
+#ifdef LDAP_R_COMPILE
+ ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
+#endif
}
#endif /* LDAP_DEBUG */
- if ( (*result = chkResponseList(ld, msgid, all)) != NULL ) {
+ if ( ( *result = chkResponseList( ld, msgid, all ) ) != NULL ) {
rc = (*result)->lm_msgtype;
} else {
#ifdef LDAP_R_COMPILE
ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex );
#endif
- for ( lc = ld->ld_conns; lc != NULL; lc = nextlc ) {
- nextlc = lc->lconn_next;
+ for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {
if ( ber_sockbuf_ctrl( lc->lconn_sb,
- LBER_SB_OPT_DATA_READY, NULL ) ) {
+ LBER_SB_OPT_DATA_READY, NULL ) )
+ {
#ifdef LDAP_R_COMPILE
ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex );
#endif
if ( rc == -1 ) {
Debug( LDAP_DEBUG_TRACE,
"ldap_int_select returned -1: errno %d\n",
- errno, 0, 0 );
+ sock_errno(), 0, 0 );
}
#endif
if ( rc == 0 || ( rc == -1 && (
!LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_RESTART)
- || errno != EINTR )))
+ || sock_errno() != EINTR ) ) )
{
ld->ld_errno = (rc == -1 ? LDAP_SERVER_DOWN :
LDAP_TIMEOUT);
if ( rc == -1 ) {
rc = LDAP_MSG_X_KEEP_LOOKING; /* select interrupted: loop */
+
} else {
rc = LDAP_MSG_X_KEEP_LOOKING;
#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 = nextlc )
+ for ( lc = ld->ld_conns;
+ rc == LDAP_MSG_X_KEEP_LOOKING && lc != NULL; )
{
- nextlc = lc->lconn_next;
if ( lc->lconn_status == LDAP_CONNST_CONNECTED &&
- ldap_is_read_ready( ld, lc->lconn_sb ))
+ ldap_is_read_ready( ld, lc->lconn_sb ) )
{
#ifdef LDAP_R_COMPILE
ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex );
#endif
rc = try_read1msg( ld, msgid, all, &lc, result );
- if ( lc == NULL ) lc = nextlc;
#ifdef LDAP_R_COMPILE
ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex );
#endif
+ if ( lc == NULL ) {
+ /* if lc gets free()'d,
+ * there's no guarantee
+ * lc->lconn_next is still
+ * sane; better restart
+ * (ITS#4405) */
+ lc = ld->ld_conns;
+
+ /* don't get to next conn! */
+ break;
+ }
}
+
+ /* next conn */
+ lc = lc->lconn_next;
}
#ifdef LDAP_R_COMPILE
ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex );
retry:
if ( lc->lconn_ber == NULL ) {
- lc->lconn_ber = ldap_alloc_ber_with_options(ld);
+ lc->lconn_ber = ldap_alloc_ber_with_options( ld );
if( lc->lconn_ber == NULL ) {
return -1;
assert( LBER_VALID (ber) );
/* get the next message */
- errno = 0;
+ sock_errset(0);
#ifdef LDAP_CONNECTIONLESS
if ( LDAP_IS_UDP(ld) ) {
struct sockaddr from;
ber_int_sb_read( lc->lconn_sb, &from, sizeof(struct sockaddr) );
- if (ld->ld_options.ldo_version == LDAP_VERSION2) isv2=1;
+ if (ld->ld_options.ldo_version == LDAP_VERSION2) isv2 = 1;
}
nextresp3:
#endif
"ber_get_next failed.\n", 0, 0, 0 );
#endif
#ifdef EWOULDBLOCK
- if ( errno == EWOULDBLOCK ) return LDAP_MSG_X_KEEP_LOOKING;
+ if ( sock_errno() == EWOULDBLOCK ) return LDAP_MSG_X_KEEP_LOOKING;
#endif
#ifdef EAGAIN
- if ( errno == EAGAIN ) return LDAP_MSG_X_KEEP_LOOKING;
+ if ( sock_errno() == EAGAIN ) return LDAP_MSG_X_KEEP_LOOKING;
#endif
ld->ld_errno = LDAP_SERVER_DOWN;
return -1;
/* if it's been abandoned, toss it */
if ( ldap_abandoned( ld, id ) ) {
- Debug( LDAP_DEBUG_ANY, "abandoned ld %p msgid %ld\n",
+ Debug( LDAP_DEBUG_ANY, "abandoned/discarded ld %p msgid %ld\n",
(void *)ld, (long) id, 0);
retry_ber:
ber_free( ber, 1 );
if ( lr == NULL ) {
Debug( LDAP_DEBUG_ANY,
"no request for response on ld %p msgid %ld (tossing)\n",
- (void *)ld, (long) id, 0 );
+ (void *)ld, (long)id, 0 );
goto retry_ber;
}
#ifdef LDAP_CONNECTIONLESS
/* 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,
if ( refer_cnt > 0 ) {
/* sucessfully chased reference */
/* If haven't got end search, set chasing referrals */
- if( lr->lr_status != LDAP_REQST_COMPLETED) {
+ if ( lr->lr_status != LDAP_REQST_COMPLETED ) {
lr->lr_status = LDAP_REQST_CHASINGREFS;
Debug( LDAP_DEBUG_TRACE,
"read1msg: search ref chased, "
}
}
}
+
} else {
/* Check for V3 referral */
ber_len_t len;
!= LBER_ERROR )
{
if ( lr_res_error != NULL ) {
- {
- if ( lr->lr_res_error != NULL ) {
- (void)ldap_append_referral( ld, &lr->lr_res_error, lr_res_error );
- LDAP_FREE( (char *)lr_res_error );
+ if ( lr->lr_res_error != NULL ) {
+ (void)ldap_append_referral( ld, &lr->lr_res_error, lr_res_error );
+ LDAP_FREE( (char *)lr_res_error );
- } else {
- lr->lr_res_error = lr_res_error;
- }
+ } else {
+ lr->lr_res_error = lr_res_error;
}
lr_res_error = NULL;
}
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
* Note: refs arrary is freed by ldap_chase_v3referrals
*/
refer_cnt = ldap_chase_v3referrals( ld, lr, refs,
- 0, &lr->lr_res_error, &hadref );
+ 0, &lr->lr_res_error, &hadref );
lr->lr_status = LDAP_REQST_COMPLETED;
Debug( LDAP_DEBUG_TRACE,
"read1msg: referral chased, mark request completed, ld %p msgid %d\n",
LDAP_FREE( lr->lr_res_matched );
lr->lr_res_matched = NULL;
}
+
if( lr->lr_res_error != NULL ) {
LDAP_FREE( lr->lr_res_error );
lr->lr_res_error = NULL;
*/
if ( tag == LDAP_RES_SEARCH_RESULT )
refer_cnt = 0;
+
} else if ( ber_scanf( &tmpber, "{eAA}", &lderr,
&lr->lr_res_matched, &lr_res_error )
!= LBER_ERROR )
{
if ( lr_res_error != NULL ) {
- {
- if ( lr->lr_res_error != NULL ) {
- (void)ldap_append_referral( ld, &lr->lr_res_error, lr_res_error );
- LDAP_FREE( (char *)lr_res_error );
- } else {
- lr->lr_res_error = lr_res_error;
- }
+ if ( lr->lr_res_error != NULL ) {
+ (void)ldap_append_referral( ld, &lr->lr_res_error, lr_res_error );
+ LDAP_FREE( (char *)lr_res_error );
+ } else {
+ lr->lr_res_error = lr_res_error;
}
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;
}
ber_free( ber, 1 );
ber = NULL;
if ( refer_cnt < 0 ) {
+ ldap_return_request( ld, lr, 0 );
return( -1 ); /* fatal error */
}
lr->lr_res_errno = LDAP_SUCCESS; /* sucessfully chased referral */
+
} else {
if ( lr->lr_outrefcnt <= 0 && lr->lr_parent == NULL ) {
/* request without any referrals */
simple_request = ( hadref ? 0 : 1 );
+
} else {
/* request with referrals or child request */
ber_free( ber, 1 );
/* Check if all requests are finished, lr is now parent */
tmplr = lr;
- if (tmplr->lr_status == LDAP_REQST_COMPLETED) {
- for ( tmplr=lr->lr_child;
+ if ( tmplr->lr_status == LDAP_REQST_COMPLETED ) {
+ for ( tmplr = lr->lr_child;
tmplr != NULL;
- tmplr=tmplr->lr_refnext)
+ tmplr = tmplr->lr_refnext )
{
- if( tmplr->lr_status != LDAP_REQST_COMPLETED) break;
+ if ( tmplr->lr_status != LDAP_REQST_COMPLETED ) break;
}
}
}
}
-#ifdef LDAP_R_COMPILE
- ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
-#endif
- ldap_free_request( ld, lr );
-#ifdef LDAP_R_COMPILE
- ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
-#endif
+ ldap_return_request( ld, lr, 1 );
+ lr = NULL;
}
if ( lc != NULL ) {
}
}
+ if ( lr != NULL ) {
+ ldap_return_request( ld, lr, 0 );
+ lr = NULL;
+ }
+
if ( ber == NULL ) {
return( rc );
}
}
-static void
-merge_error_info( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr )
-{
/*
* 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 ) {
parentr->lr_res_errno = lr->lr_res_errno;
if ( lr->lr_res_error != NULL ) {
(void)ldap_append_referral( ld, &parentr->lr_res_error,
lr->lr_res_error );
}
+
} else if ( lr->lr_res_errno != LDAP_SUCCESS &&
parentr->lr_res_errno == LDAP_SUCCESS )
{
}
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",
- parentr->lr_res_errno, parentr->lr_res_error ?
- parentr->lr_res_error : "", parentr->lr_res_matched ?
- parentr->lr_res_matched : "" );
+ parentr->lr_res_errno,
+ parentr->lr_res_error ? parentr->lr_res_error : "",
+ parentr->lr_res_matched ? parentr->lr_res_matched : "" );
}
LDAP_FREE( (char *) lm );
}
- return( type );
+ return type;
}
/*
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 = NULL;
#ifdef LDAP_R_COMPILE
ldap_pvt_thread_mutex_lock( &ld->ld_res_mutex );
#endif
+ prev = NULL;
for ( lm = ld->ld_responses; lm != NULL; lm = lm->lm_next ) {
- if ( lm->lm_msgid == msgid )
+ if ( lm->lm_msgid == msgid ) {
break;
+ }
prev = lm;
}
if ( lm == NULL ) {
rc = -1;
+
} else {
- if ( prev == NULL )
+ if ( prev == NULL ) {
ld->ld_responses = lm->lm_next;
- else
+ } else {
prev->lm_next = lm->lm_next;
+ }
}
#ifdef LDAP_R_COMPILE
ldap_pvt_thread_mutex_unlock( &ld->ld_res_mutex );
#endif
- if ( lm && ldap_msgfree( lm ) == LDAP_RES_SEARCH_ENTRY )
+ if ( lm && ldap_msgfree( lm ) == LDAP_RES_SEARCH_ENTRY ) {
rc = -1;
+ }
- return( rc );
+ return rc;
}
/*
- * ldap_abandoned
+ * ldap_abandoned_idx
*
- * return 1 if message msgid is waiting to be abandoned, 0 otherwise
+ * 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
-ldap_abandoned( LDAP *ld, ber_int_t msgid )
+ldap_abandoned_idx( LDAP *ld, ber_int_t msgid )
{
- int i;
+ int begin,
+ end;
#ifdef LDAP_R_COMPILE
LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex );
#endif
- if ( ld->ld_abandoned == NULL )
- return( 0 );
+ assert( ld->ld_nabandoned >= 0 );
- for ( i = 0; ld->ld_abandoned[i] != -1; i++ )
- if ( ld->ld_abandoned[i] == msgid )
- return( 1 );
+ if ( ld->ld_abandoned == NULL || ld->ld_nabandoned == 0 ) {
+ return -1;
+ }
- return( 0 );
-}
+ begin = 0;
+ end = ld->ld_nabandoned - 1;
+
+ /* use bisection */
+ if ( msgid < ld->ld_abandoned[ begin ] ) {
+ return -1;
+ }
+
+ if ( msgid > ld->ld_abandoned[ end ] ) {
+ return -1;
+ }
+
+ while ( end >= begin ) {
+ int pos = (begin + end)/2;
+ int curid = ld->ld_abandoned[ pos ];
+ if ( msgid < curid ) {
+ end = pos - 1;
+
+ } else if ( msgid > curid ) {
+ begin = pos + 1;
+
+ } else {
+ return pos;
+ }
+ }
+
+ /* not abandoned */
+ return -1;
+}
/*
* ldap_mark_abandoned
static int
ldap_mark_abandoned( LDAP *ld, ber_int_t msgid )
{
- int i;
+ int i, idx;
#ifdef LDAP_R_COMPILE
LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex );
#endif
- 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 );
+ idx = ldap_abandoned_idx( ld, msgid );
+ if ( idx == -1 ) {
+ return -1;
+ }
- for ( ; ld->ld_abandoned[i] != -1; i++ ) {
- ld->ld_abandoned[i] = ld->ld_abandoned[i + 1];
+ --ld->ld_nabandoned;
+ assert( ld->ld_nabandoned >= 0 );
+ for ( i = idx; i < ld->ld_nabandoned; i++ ) {
+ ld->ld_abandoned[ i ] = ld->ld_abandoned[ i + 1 ];
}
- return( 0 );
+ return 0;
}