#include "ldap-int.h"
-static int do_abandon LDAP_P((
+static int
+do_abandon(
LDAP *ld,
ber_int_t origid,
ber_int_t msgid,
LDAPControl **sctrls,
- LDAPControl **cctrls));
+ int sendabandon );
/*
* ldap_abandon_ext - perform an ldap extended abandon operation.
LDAPControl **sctrls,
LDAPControl **cctrls )
{
- int rc;
+ int rc;
+
Debug( LDAP_DEBUG_TRACE, "ldap_abandon_ext %d\n", msgid, 0, 0 );
/* check client controls */
#ifdef LDAP_R_COMPILE
ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
#endif
+
rc = ldap_int_client_controls( ld, cctrls );
- if( rc == LDAP_SUCCESS )
- rc = do_abandon( ld, msgid, msgid, sctrls, cctrls );
+ if ( rc == LDAP_SUCCESS ) {
+ rc = do_abandon( ld, msgid, msgid, sctrls, 1 );
+ }
#ifdef LDAP_R_COMPILE
ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
#endif
+
return rc;
}
}
+int
+ldap_int_discard(
+ LDAP *ld,
+ ber_int_t msgid )
+{
+ int rc;
+
+#ifdef LDAP_R_COMPILE
+ ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
+#endif
+
+ rc = do_abandon( ld, msgid, msgid, NULL, 0 );
+
+#ifdef LDAP_R_COMPILE
+ ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
+#endif
+
+ return rc;
+}
+
static int
do_abandon(
LDAP *ld,
ber_int_t origid,
ber_int_t msgid,
LDAPControl **sctrls,
- LDAPControl **cctrls )
+ int sendabandon )
{
BerElement *ber;
- int i, err, sendabandon;
+ int i, err;
ber_int_t *old_abandon;
Sockbuf *sb;
LDAPRequest *lr;
- Debug( LDAP_DEBUG_TRACE, "do_abandon origid %d, msgid %d\n",
+ Debug( LDAP_DEBUG_TRACE, "ldap_int_discard origid %d, msgid %d\n",
origid, msgid, 0 );
- sendabandon = 1;
-
/* find the request that we are abandoning */
start_again:;
lr = ld->ld_requests;
}
if ( lr->lr_origid == msgid ) {/* child: abandon it */
- (void)do_abandon( ld,
- lr->lr_origid, lr->lr_msgid, sctrls, cctrls );
+ (void)do_abandon( ld, lr->lr_origid, lr->lr_msgid,
+ sctrls, sendabandon );
/* restart, as lr may now be dangling... */
goto start_again;
}
}
-/* ldap_msgdelete locks the res_mutex. Give up the req_mutex
- * while we're in there.
- */
+ /* ldap_msgdelete locks the res_mutex. Give up the req_mutex
+ * while we're in there.
+ */
#ifdef LDAP_R_COMPILE
ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
#endif
/* fetch again the request that we are abandoning */
if ( lr != NULL ) {
for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) {
- if ( lr->lr_msgid == msgid ) { /* this message */
+ /* this message */
+ if ( lr->lr_msgid == msgid ) {
break;
}
}
err = 0;
if ( sendabandon ) {
- if( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, NULL ) == -1 ) {
+ if ( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, NULL ) == -1 ) {
/* not connected */
err = -1;
ld->ld_errno = LDAP_SERVER_DOWN;
- } else if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
- /* BER element alocation failed */
+ } else if ( ( ber = ldap_alloc_ber_with_options( ld ) ) == NULL ) {
+ /* BER element allocation failed */
err = -1;
ld->ld_errno = LDAP_NO_MEMORY;
} else {
- /*
- * We already have the mutex in LDAP_R_COMPILE, so
- * don't try to get it again.
- * LDAP_NEXT_MSGID(ld, i);
- */
+ /*
+ * We already have the mutex in LDAP_R_COMPILE, so
+ * don't try to get it again.
+ * LDAP_NEXT_MSGID(ld, i);
+ */
+
i = ++(ld)->ld_msgid;
#ifdef LDAP_CONNECTIONLESS
if ( LDAP_IS_UDP(ld) ) {
LDAP_REQ_ABANDON, msgid );
}
- if( err == -1 ) {
+ if ( err == -1 ) {
/* encoding error */
ld->ld_errno = LDAP_ENCODING_ERROR;
/* close '{' */
err = ber_printf( ber, /*{*/ "N}" );
- if( err == -1 ) {
+ if ( err == -1 ) {
/* encoding error */
ld->ld_errno = LDAP_ENCODING_ERROR;
}
if ( sendabandon || lr->lr_status == LDAP_REQST_WRITING ) {
ldap_free_connection( ld, lr->lr_conn, 0, 1 );
}
+
if ( origid == msgid ) {
ldap_free_request( ld, lr );
}
ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
ldap_pvt_thread_mutex_lock( &ld->ld_res_mutex );
#endif
+
+ /* use bisection */
i = 0;
if ( ld->ld_abandoned != NULL ) {
- for ( ; ld->ld_abandoned[i] != -1; i++ )
- ; /* NULL */
- }
+ int begin,
+ end;
+
+ assert( ld->ld_nabandoned >= 0 );
+
+ begin = 0;
+ end = ld->ld_nabandoned - 1;
- old_abandon = ld->ld_abandoned;
+ if ( ld->ld_nabandoned == 0 || ld->ld_abandoned[ begin ] > msgid ) {
+ i = 0;
- ld->ld_abandoned = (ber_int_t *) LDAP_REALLOC( (char *)
- ld->ld_abandoned, (i + 2) * sizeof(ber_int_t) );
-
- if ( ld->ld_abandoned == NULL ) {
- ld->ld_abandoned = old_abandon;
- ld->ld_errno = LDAP_NO_MEMORY;
- goto done;
+ } else if ( ld->ld_abandoned[ end ] < msgid ) {
+ i = ld->ld_nabandoned;
+
+ } else {
+ int pos, curid;
+
+ while ( end >= begin ) {
+ pos = (begin + end)/2;
+ curid = ld->ld_abandoned[ pos ];
+
+ if ( msgid < curid ) {
+ end = pos - 1;
+
+ } else if ( msgid > curid ) {
+ begin = pos + 1;
+
+ } else {
+ /* already abandoned? */
+ i = -1;
+ break;
+ }
+ }
+
+ if ( i == 0 ) {
+ i = pos;
+ }
+ }
}
- ld->ld_abandoned[i] = msgid;
- ld->ld_abandoned[i + 1] = -1;
+ if ( i != -1 ) {
+ int pos = i;
+
+ old_abandon = ld->ld_abandoned;
+
+ ld->ld_abandoned = (ber_int_t *) LDAP_REALLOC( (char *)ld->ld_abandoned,
+ ( ld->ld_nabandoned + 1 ) * sizeof( ber_int_t ) );
+
+ if ( ld->ld_abandoned == NULL ) {
+ ld->ld_abandoned = old_abandon;
+ ld->ld_errno = LDAP_NO_MEMORY;
+ goto done;
+ }
+
+ for ( i = ld->ld_nabandoned; i > pos; i-- ) {
+ ld->ld_abandoned[ i ] = ld->ld_abandoned[ i - 1 ];
+ }
+ ld->ld_abandoned[ pos ] = msgid;
+ ++ld->ld_nabandoned;
+ }
if ( err != -1 ) {
ld->ld_errno = LDAP_SUCCESS;
ldap_pvt_thread_mutex_t ld_res_mutex;
#endif
- ber_int_t *ld_abandoned; /* array of abandoned requests */
+ ber_len_t ld_nabandoned;
+ ber_int_t *ld_abandoned; /* array of abandoned requests */
LDAPCache *ld_cache; /* non-null if cache is initialized */
#define LDAP_NEXT_MSGID(ld, id) id = ++(ld)->ld_msgid
#endif
+LDAP_F ( int )
+ldap_int_discard LDAP_P((
+ LDAP *ld,
+ ber_int_t msgid ));
+
/*
* in init.c
*/
#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;
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;
}
}
if ( LDAP_BACK_IGNORE( li ) ) {
- return LDAP_SUCCESS;
+ return ldap_int_discard( lc->lc_ld, msgid );
}
if ( LDAP_BACK_CANCEL( li ) ) {
rc = ldap_abandon_ext( msc->msc_ld, msgid, NULL, NULL );
} else if ( META_BACK_TGT_IGNORE( mt ) ) {
- rc = LDAP_SUCCESS;
+ rc = ldap_int_discard( msc->msc_ld, msgid );
} else if ( META_BACK_TGT_CANCEL( mt ) ) {
rc = ldap_cancel_s( msc->msc_ld, msgid, NULL, NULL );