/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
- * Copyright 1998-2008 The OpenLDAP Foundation.
+ * Copyright 1998-2012 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
#include "ldap_log.h"
#include "lutil.h"
-static int ldap_abandoned LDAP_P(( LDAP *ld, ber_int_t msgid, int *idx ));
-static int ldap_mark_abandoned LDAP_P(( LDAP *ld, ber_int_t msgid, int idx ));
+static int ldap_abandoned LDAP_P(( LDAP *ld, ber_int_t msgid ));
+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 ));
static ber_tag_t try_read1msg LDAP_P(( LDAP *ld, ber_int_t msgid,
- int all, LDAPConn **lc, LDAPMessage **result ));
+ int all, LDAPConn *lc, LDAPMessage **result ));
static ber_tag_t build_result_ber LDAP_P(( LDAP *ld, BerElement **bp, LDAPRequest *lr ));
static void merge_error_info LDAP_P(( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr ));
static LDAPMessage * chkResponseList LDAP_P(( LDAP *ld, int msgid, int all));
struct timeval *timeout,
LDAPMessage **result )
{
- LDAPMessage *lm = NULL;
int rc;
assert( ld != NULL );
Debug( LDAP_DEBUG_TRACE, "ldap_result ld %p msgid %d\n", (void *)ld, msgid, 0 );
-#ifdef LDAP_R_COMPILE
- ldap_pvt_thread_mutex_lock( &ld->ld_res_mutex );
-#endif
-
-#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
+ LDAP_MUTEX_LOCK( &ld->ld_res_mutex );
+ rc = wait4msg( ld, msgid, all, timeout, result );
+ LDAP_MUTEX_UNLOCK( &ld->ld_res_mutex );
return rc;
}
+/* protected by res_mutex */
static LDAPMessage *
chkResponseList(
LDAP *ld,
* wait until it arrives or timeout occurs.
*/
-#ifdef LDAP_R_COMPILE
- LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex );
-#endif
+ LDAP_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex );
Debug( LDAP_DEBUG_TRACE,
"ldap_chkResponseList ld %p msgid %d all %d\n",
lastlm = &ld->ld_responses;
for ( lm = ld->ld_responses; lm != NULL; lm = nextlm ) {
- int idx;
-
nextlm = lm->lm_next;
++cnt;
- if ( ldap_abandoned( ld, lm->lm_msgid, &idx ) ) {
+ if ( ldap_abandoned( ld, lm->lm_msgid ) ) {
Debug( LDAP_DEBUG_ANY,
"response list msg abandoned, "
"msgid %d message type %s\n",
default:
/* there's no need to keep the id
* in the abandoned list any longer */
- ldap_mark_abandoned( ld, lm->lm_msgid, idx );
+ ldap_mark_abandoned( ld, lm->lm_msgid );
break;
}
return lm;
}
+/* protected by res_mutex */
static int
wait4msg(
LDAP *ld,
assert( ld != NULL );
assert( result != NULL );
-#ifdef LDAP_R_COMPILE
- LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex );
-#endif
+ LDAP_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex );
if ( timeout == NULL && ld->ld_options.ldo_tm_api.tv_sec >= 0 ) {
tv = ld->ld_options.ldo_tm_api;
}
#endif /* LDAP_DEBUG */
- if ( timeout != NULL ) {
+ if ( timeout != NULL && timeout->tv_sec != -1 ) {
tv0 = *timeout;
tv = *timeout;
tvp = &tv;
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_MUTEX_LOCK( &ld->ld_req_mutex );
ldap_dump_requests_and_responses( ld );
-#ifdef LDAP_R_COMPILE
- ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
-#endif
+ LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
}
#endif /* LDAP_DEBUG */
} else {
int lc_ready = 0;
-#ifdef LDAP_R_COMPILE
- ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex );
-#endif
+ LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {
if ( ber_sockbuf_ctrl( lc->lconn_sb,
LBER_SB_OPT_DATA_READY, NULL ) )
{
-#ifdef LDAP_R_COMPILE
- ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex );
-#endif
- rc = try_read1msg( ld, msgid, all, &lc, result );
-#ifdef LDAP_R_COMPILE
- ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex );
-#endif
lc_ready = 1;
break;
}
}
-#ifdef LDAP_R_COMPILE
- ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex );
-#endif
if ( !lc_ready ) {
+ int err;
rc = ldap_int_select( ld, tvp );
-#ifdef LDAP_DEBUG
if ( rc == -1 ) {
+ err = sock_errno();
+#ifdef LDAP_DEBUG
Debug( LDAP_DEBUG_TRACE,
"ldap_int_select returned -1: errno %d\n",
- sock_errno(), 0, 0 );
- }
+ err, 0, 0 );
#endif
+ }
if ( rc == 0 || ( rc == -1 && (
!LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_RESTART)
- || sock_errno() != EINTR ) ) )
+ || err != EINTR ) ) )
{
ld->ld_errno = (rc == -1 ? LDAP_SERVER_DOWN :
LDAP_TIMEOUT);
+ LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
return( rc );
}
rc = LDAP_MSG_X_KEEP_LOOKING; /* select interrupted: loop */
} else {
- rc = LDAP_MSG_X_KEEP_LOOKING;
-#ifdef LDAP_R_COMPILE
- ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
-#endif
- if ( ld->ld_requests &&
- ld->ld_requests->lr_status == LDAP_REQST_WRITING &&
- ldap_is_write_ready( ld,
- ld->ld_requests->lr_conn->lconn_sb ) )
- {
- ldap_int_flush_request( ld, ld->ld_requests );
- }
-#ifdef LDAP_R_COMPILE
- ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
- ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex );
-#endif
- for ( lc = ld->ld_conns;
- rc == LDAP_MSG_X_KEEP_LOOKING && lc != NULL; )
+ lc_ready = 1;
+ }
+ }
+ if ( lc_ready ) {
+ LDAPConn *lnext;
+ int serviced = 0;
+ rc = LDAP_MSG_X_KEEP_LOOKING;
+ LDAP_MUTEX_LOCK( &ld->ld_req_mutex );
+ if ( ld->ld_requests &&
+ ld->ld_requests->lr_status == LDAP_REQST_WRITING &&
+ ldap_is_write_ready( ld,
+ ld->ld_requests->lr_conn->lconn_sb ) )
+ {
+ serviced = 1;
+ ldap_int_flush_request( ld, ld->ld_requests );
+ }
+ for ( lc = ld->ld_conns;
+ rc == LDAP_MSG_X_KEEP_LOOKING && lc != NULL;
+ lc = lnext )
+ {
+ if ( lc->lconn_status == LDAP_CONNST_CONNECTED &&
+ ldap_is_read_ready( ld, lc->lconn_sb ) )
{
- if ( lc->lconn_status == LDAP_CONNST_CONNECTED &&
- 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 );
-#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;
- }
+ serviced = 1;
+ /* Don't let it get freed out from under us */
+ ++lc->lconn_refcnt;
+ rc = try_read1msg( ld, msgid, all, lc, result );
+ lnext = lc->lconn_next;
+
+ /* Only take locks if we're really freeing */
+ if ( lc->lconn_refcnt <= 1 ) {
+ ldap_free_connection( ld, lc, 0, 1 );
+ } else {
+ --lc->lconn_refcnt;
}
-
- /* next conn */
- lc = lc->lconn_next;
+ } else {
+ lnext = lc->lconn_next;
}
-#ifdef LDAP_R_COMPILE
- ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex );
-#endif
}
+ LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
+ /* Quit looping if no one handled any events */
+ if (!serviced)
+ rc = -1;
}
+ LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
}
if ( rc == LDAP_MSG_X_KEEP_LOOKING && tvp != NULL ) {
}
+/* protected by res_mutex, conn_mutex and req_mutex */
static ber_tag_t
try_read1msg(
LDAP *ld,
ber_int_t msgid,
int all,
- LDAPConn **lcp,
+ LDAPConn *lc,
LDAPMessage **result )
{
BerElement *ber;
LDAPMessage *newmsg, *l, *prev;
ber_int_t id;
- int idx;
ber_tag_t tag;
ber_len_t len;
int foundit = 0;
LDAPRequest *lr, *tmplr, dummy_lr = { 0 };
- LDAPConn *lc;
BerElement tmpber;
- int rc, refer_cnt, hadref, simple_request;
+ int rc, refer_cnt, hadref, simple_request, err;
ber_int_t lderr;
#ifdef LDAP_CONNECTIONLESS
#endif
assert( ld != NULL );
- assert( lcp != NULL );
- assert( *lcp != NULL );
+ assert( lc != NULL );
-#ifdef LDAP_R_COMPILE
- LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex );
-#endif
+ LDAP_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex );
+ LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex );
+ LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex );
Debug( LDAP_DEBUG_TRACE, "read1msg: ld %p msgid %d all %d\n",
(void *)ld, msgid, all );
- lc = *lcp;
-
retry:
if ( lc->lconn_ber == NULL ) {
lc->lconn_ber = ldap_alloc_ber_with_options( ld );
break;
case LBER_DEFAULT:
+ err = sock_errno();
#ifdef LDAP_DEBUG
Debug( LDAP_DEBUG_CONNS,
"ber_get_next failed.\n", 0, 0, 0 );
#endif
-#ifdef EWOULDBLOCK
- if ( sock_errno() == EWOULDBLOCK ) return LDAP_MSG_X_KEEP_LOOKING;
-#endif
-#ifdef EAGAIN
- if ( sock_errno() == EAGAIN ) return LDAP_MSG_X_KEEP_LOOKING;
-#endif
+ if ( err == EWOULDBLOCK ) return LDAP_MSG_X_KEEP_LOOKING;
+ if ( err == EAGAIN ) return LDAP_MSG_X_KEEP_LOOKING;
ld->ld_errno = LDAP_SERVER_DOWN;
-#ifdef LDAP_R_COMPILE
- ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
-#endif
- ldap_free_connection( ld, lc, 1, 0 );
-#ifdef LDAP_R_COMPILE
- ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
-#endif
- lc = *lcp = NULL;
+ --lc->lconn_refcnt;
+ lc->lconn_status = 0;
return -1;
default:
/* if it's been abandoned, toss it */
if ( id > 0 ) {
- if ( ldap_abandoned( ld, id, &idx ) ) {
+ if ( ldap_abandoned( ld, id ) ) {
/* the message type */
tag = ber_peek_tag( ber, &len );
switch ( tag ) {
default:
/* there's no need to keep the id
* in the abandoned list any longer */
- ldap_mark_abandoned( ld, id, idx );
+ ldap_mark_abandoned( ld, id );
break;
}
ber_scanf(ber, "x{");
}
nextresp2:
+ ;
#endif
}
}
/* Do we need to check for referrals? */
- if ( LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_REFERRALS) ||
- lr->lr_parent != NULL )
+ if ( tag != LDAP_RES_BIND &&
+ ( LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_REFERRALS) ||
+ lr->lr_parent != NULL ))
{
char **refs = NULL;
ber_len_t len;
return( -1 ); /* fatal error */
}
lr->lr_res_errno = LDAP_SUCCESS; /* sucessfully chased referral */
+ if ( lr->lr_res_matched ) {
+ LDAP_FREE( lr->lr_res_matched );
+ lr->lr_res_matched = NULL;
+ }
} else {
if ( lr->lr_outrefcnt <= 0 && lr->lr_parent == NULL ) {
Debug( LDAP_DEBUG_TRACE,
"read1msg: mark request completed, ld %p msgid %d\n",
(void *)ld, lr->lr_msgid, 0);
+ tmplr = lr;
while ( lr->lr_parent != NULL ) {
merge_error_info( ld, lr->lr_parent, lr );
break; /* not completely done yet */
}
}
+ /* ITS#6744: Original lr was refcounted when we retrieved it,
+ * must release it now that we're working with the parent
+ */
+ if ( tmplr->lr_parent ) {
+ ldap_return_request( ld, tmplr, 0 );
+ }
/* Check if all requests are finished, lr is now parent */
tmplr = lr;
}
/*
- * RF 4511 unsolicited (id == 0) responses
+ * RFC 4511 unsolicited (id == 0) responses
* shouldn't necessarily end the connection
*/
if ( lc != NULL && id != 0 ) {
-#ifdef LDAP_R_COMPILE
- ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
-#endif
- ldap_free_connection( ld, lc, 0, 1 );
-#ifdef LDAP_R_COMPILE
- ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
-#endif
- lc = *lcp = NULL;
+ --lc->lconn_refcnt;
+ lc = NULL;
}
}
}
/* get rid of the connection... */
if ( lc != NULL ) {
-#ifdef LDAP_R_COMPILE
- ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
-#endif
- ldap_free_connection( ld, lc, 0, 1 );
-#ifdef LDAP_R_COMPILE
- ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
-#endif
- lc = *lcp = NULL;
+ --lc->lconn_refcnt;
}
/* need to return -1, because otherwise
* a valid result is expected */
+ ld->ld_errno = lderr;
return -1;
}
}
if ( msgid == LDAP_RES_ANY || id == msgid ) {
if ( all == LDAP_MSG_ONE
|| ( newmsg->lm_msgtype != LDAP_RES_SEARCH_RESULT
- && newmsg->lm_msgtype != LDAP_RES_SEARCH_ENTRY
+ && newmsg->lm_msgtype != LDAP_RES_SEARCH_ENTRY
+ && newmsg->lm_msgtype != LDAP_RES_INTERMEDIATE
&& newmsg->lm_msgtype != LDAP_RES_SEARCH_REFERENCE ) )
{
*result = newmsg;
Debug( LDAP_DEBUG_TRACE, "ldap_msgdelete ld=%p msgid=%d\n",
(void *)ld, msgid, 0 );
-#ifdef LDAP_R_COMPILE
- ldap_pvt_thread_mutex_lock( &ld->ld_res_mutex );
-#endif
+ LDAP_MUTEX_LOCK( &ld->ld_res_mutex );
prev = NULL;
for ( lm = ld->ld_responses; lm != NULL; lm = lm->lm_next ) {
if ( lm->lm_msgid == msgid ) {
prev->lm_next = lm->lm_next;
}
}
-#ifdef LDAP_R_COMPILE
- ldap_pvt_thread_mutex_unlock( &ld->ld_res_mutex );
-#endif
+ LDAP_MUTEX_UNLOCK( &ld->ld_res_mutex );
if ( lm ) {
switch ( ldap_msgfree( lm ) ) {
case LDAP_RES_SEARCH_ENTRY:
*
* 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, int *idxp )
+ldap_abandoned( LDAP *ld, ber_int_t msgid )
{
-#ifdef LDAP_R_COMPILE
- LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex );
-#endif
-
- assert( idxp != NULL );
+ int ret, idx;
assert( msgid >= 0 );
- assert( ld->ld_nabandoned >= 0 );
- return ldap_int_bisect_find( ld->ld_abandoned, ld->ld_nabandoned, msgid, idxp );
+ LDAP_MUTEX_LOCK( &ld->ld_abandon_mutex );
+ ret = ldap_int_bisect_find( ld->ld_abandoned, ld->ld_nabandoned, msgid, &idx );
+ LDAP_MUTEX_UNLOCK( &ld->ld_abandon_mutex );
+ return ret;
}
/*
* ldap_mark_abandoned
- *
- * expects ld_res_mutex to be locked
*/
static int
-ldap_mark_abandoned( LDAP *ld, ber_int_t msgid, int idx )
+ldap_mark_abandoned( LDAP *ld, ber_int_t msgid )
{
-#ifdef LDAP_R_COMPILE
- LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex );
-#endif
-
- /* NOTE: those assertions are repeated in ldap_int_bisect_delete() */
- assert( idx >= 0 );
- assert( idx < ld->ld_nabandoned );
- assert( ld->ld_abandoned[ idx ] == msgid );
+ int ret, idx;
- return ldap_int_bisect_delete( &ld->ld_abandoned, &ld->ld_nabandoned,
+ assert( msgid >= 0 );
+ LDAP_MUTEX_LOCK( &ld->ld_abandon_mutex );
+ ret = ldap_int_bisect_find( ld->ld_abandoned, ld->ld_nabandoned, msgid, &idx );
+ if (ret <= 0) { /* error or already deleted by another thread */
+ LDAP_MUTEX_UNLOCK( &ld->ld_abandon_mutex );
+ return ret;
+ }
+ /* still in abandoned array, so delete */
+ ret = ldap_int_bisect_delete( &ld->ld_abandoned, &ld->ld_nabandoned,
msgid, idx );
+ LDAP_MUTEX_UNLOCK( &ld->ld_abandon_mutex );
+ return ret;
}