do_abandon(
LDAP *ld,
ber_int_t origid,
- ber_int_t msgid,
+ LDAPRequest *lr,
LDAPControl **sctrls,
int sendabandon );
rc = ldap_int_client_controls( ld, cctrls );
if ( rc == LDAP_SUCCESS ) {
- rc = do_abandon( ld, msgid, msgid, sctrls, 1 );
+ rc = do_abandon( ld, msgid, NULL, sctrls, 1 );
}
LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
int rc;
LDAP_MUTEX_LOCK( &ld->ld_req_mutex );
- rc = do_abandon( ld, msgid, msgid, NULL, 0 );
+ rc = do_abandon( ld, msgid, NULL, NULL, 0 );
LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
return rc;
}
do_abandon(
LDAP *ld,
ber_int_t origid,
- ber_int_t msgid,
+ LDAPRequest *lr,
LDAPControl **sctrls,
int sendabandon )
{
BerElement *ber;
int i, err;
+ ber_int_t msgid = origid;
Sockbuf *sb;
- LDAPRequest *lr;
-
- Debug2( LDAP_DEBUG_TRACE, "do_abandon origid %d, msgid %d\n",
- origid, msgid );
-
- /* find the request that we are abandoning */
-start_again:;
- lr = ld->ld_requests;
- while ( lr != NULL ) {
- /* this message */
- if ( lr->lr_msgid == msgid ) {
- break;
- }
-
- /* child: abandon it */
- if ( lr->lr_origid == msgid && !lr->lr_abandoned ) {
- (void)do_abandon( ld, lr->lr_origid, lr->lr_msgid,
- sctrls, sendabandon );
-
- /* restart, as lr may now be dangling... */
- goto start_again;
- }
+ LDAPRequest needle = {0};
- lr = lr->lr_next;
- }
+ needle.lr_msgid = origid;
if ( lr != NULL ) {
- if ( origid == msgid && lr->lr_parent != NULL ) {
+ msgid = lr->lr_msgid;
+ Debug2( LDAP_DEBUG_TRACE, "do_abandon origid %d, msgid %d\n",
+ origid, msgid );
+ } else if ( (lr = ldap_tavl_find( ld->ld_requests, &needle, ldap_req_cmp )) != NULL ) {
+ Debug2( LDAP_DEBUG_TRACE, "do_abandon origid %d, msgid %d\n",
+ origid, msgid );
+ if ( lr->lr_parent != NULL ) {
/* don't let caller abandon child requests! */
ld->ld_errno = LDAP_PARAM_ERROR;
return( LDAP_PARAM_ERROR );
}
+ msgid = lr->lr_msgid;
+ }
+
+ if ( lr != NULL ) {
+ LDAPRequest **childp = &lr->lr_child;
+
+ needle.lr_msgid = lr->lr_msgid;
+
if ( lr->lr_status != LDAP_REQST_INPROGRESS ) {
/* no need to send abandon message */
sendabandon = 0;
}
+
+ while ( *childp ) {
+ /* Abandon children */
+ LDAPRequest *child = *childp;
+
+ (void)do_abandon( ld, lr->lr_origid, child, sctrls, sendabandon );
+ if ( *childp == child ) {
+ childp = &child->lr_refnext;
+ }
+ }
}
/* ldap_msgdelete locks the res_mutex. Give up the req_mutex
/* fetch again the request that we are abandoning */
if ( lr != NULL ) {
- for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) {
- /* this message */
- if ( lr->lr_msgid == msgid ) {
- break;
- }
- }
+ lr = ldap_tavl_find( ld->ld_requests, &needle, ldap_req_cmp );
}
err = 0;
* request to be in WRITING state.
*/
rc = 0;
- if ( ld->ld_requests &&
- ld->ld_requests->lr_status == LDAP_REQST_WRITING &&
- ldap_int_flush_request( ld, ld->ld_requests ) < 0 )
- {
- rc = -1;
+ if ( ld->ld_requests != NULL ) {
+ TAvlnode *node = ldap_tavl_end( ld->ld_requests, TAVL_DIR_RIGHT );
+ LDAPRequest *lr;
+
+ assert( node != NULL );
+ lr = node->avl_data;
+ if ( lr->lr_status == LDAP_REQST_WRITING &&
+ ldap_int_flush_request( ld, lr ) < 0 ) {
+ rc = -1;
+ }
}
if ( rc ) {
ber_free( ber, 1 );
}
}
- lr->lr_prev = NULL;
- lr->lr_next = ld->ld_requests;
- if ( lr->lr_next != NULL ) {
- lr->lr_next->lr_prev = lr;
- }
- ld->ld_requests = lr;
+ rc = ldap_tavl_insert( &ld->ld_requests, lr, ldap_req_cmp, ldap_avl_dup_error );
+ assert( rc == LDAP_SUCCESS );
ld->ld_errno = LDAP_SUCCESS;
if ( ldap_int_flush_request( ld, lr ) == -1 ) {
/* FIXME: is this at all possible?
* ldap_ld_free() in unbind.c calls ldap_free_connection()
* with force == 1 __after__ explicitly calling
- * ldap_free_request() on all requests */
+ * ldap_tavl_free on ld->ld_requests */
if ( force ) {
- LDAPRequest *lr;
-
- for ( lr = ld->ld_requests; lr; ) {
- LDAPRequest *lr_next = lr->lr_next;
-
- if ( lr->lr_conn == lc ) {
- ldap_free_request_int( ld, lr );
- }
-
- lr = lr_next;
- }
+ ldap_tavl_free( ld->ld_requests, ldap_do_free_request );
+ ld->ld_requests = NULL;
}
if ( lc->lconn_sb != ld->ld_sb ) {
void
ldap_dump_requests_and_responses( LDAP *ld )
{
- LDAPRequest *lr;
LDAPMessage *lm, *l;
+ TAvlnode *node;
int i;
Debug1( LDAP_DEBUG_TRACE, "** ld %p Outstanding Requests:\n",
(void *)ld );
- lr = ld->ld_requests;
- if ( lr == NULL ) {
+ node = ldap_tavl_end( ld->ld_requests, TAVL_DIR_LEFT );
+ if ( node == NULL ) {
Debug0( LDAP_DEBUG_TRACE, " Empty\n" );
}
- for ( i = 0; lr != NULL; lr = lr->lr_next, i++ ) {
+ for ( i = 0 ; node != NULL; i++, node = ldap_tavl_next( node, TAVL_DIR_RIGHT ) ) {
+ LDAPRequest *lr = node->avl_data;
+
Debug3( LDAP_DEBUG_TRACE, " * msgid %d, origid %d, status %s\n",
lr->lr_msgid, lr->lr_origid,
( lr->lr_status == LDAP_REQST_INPROGRESS ) ? "InProgress" :
#endif /* LDAP_DEBUG */
/* protected by req_mutex */
-static void
-ldap_free_request_int( LDAP *ld, LDAPRequest *lr )
+void
+ldap_do_free_request( void *arg )
{
- LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex );
+ LDAPRequest *lr = arg;
+
+ Debug3( LDAP_DEBUG_TRACE, "ldap_do_free_request: "
+ "asked to free lr %p msgid %d refcnt %d\n",
+ lr, lr->lr_msgid, lr->lr_refcnt );
/* if lr_refcnt > 0, the request has been looked up
* by ldap_find_request_by_msgid(); if in the meanwhile
* the request is free()'d by someone else, just decrease
- * the reference count and extract it from the request
- * list; later on, it will be freed. */
- if ( lr->lr_prev == NULL ) {
- if ( lr->lr_refcnt == 0 ) {
- /* free'ing the first request? */
- assert( ld->ld_requests == lr );
- }
-
- if ( ld->ld_requests == lr ) {
- ld->ld_requests = lr->lr_next;
- }
-
- } else {
- lr->lr_prev->lr_next = lr->lr_next;
- }
-
- if ( lr->lr_next != NULL ) {
- lr->lr_next->lr_prev = lr->lr_prev;
- }
-
+ * the reference count; later on, it will be freed. */
if ( lr->lr_refcnt > 0 ) {
+ assert( lr->lr_refcnt == 1 );
lr->lr_refcnt = -lr->lr_refcnt;
-
- lr->lr_prev = NULL;
- lr->lr_next = NULL;
-
return;
}
LDAP_FREE( lr );
}
+int
+ldap_req_cmp( const void *l, const void *r )
+{
+ const LDAPRequest *left = l, *right = r;
+ return left->lr_msgid - right->lr_msgid;
+}
+
+/* protected by req_mutex */
+static void
+ldap_free_request_int( LDAP *ld, LDAPRequest *lr )
+{
+ LDAPRequest *removed;
+
+ LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex );
+ removed = ldap_tavl_delete( &ld->ld_requests, lr, ldap_req_cmp );
+ assert( !removed || removed == lr );
+ Debug3( LDAP_DEBUG_TRACE, "ldap_free_request_int: "
+ "lr %p msgid %d%s removed\n",
+ lr, lr->lr_msgid, removed ? "" : " not" );
+
+ ldap_do_free_request( lr );
+}
+
/* protected by req_mutex */
void
ldap_free_request( LDAP *ld, LDAPRequest *lr )
LDAPRequest *
ldap_find_request_by_msgid( LDAP *ld, ber_int_t msgid )
{
- LDAPRequest *lr;
-
- for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) {
- if ( lr->lr_status == LDAP_REQST_COMPLETED ) {
- continue; /* Skip completed requests */
- }
- if ( msgid == lr->lr_msgid ) {
- lr->lr_refcnt++;
- break;
- }
+ LDAPRequest *lr, needle = {0};
+ needle.lr_msgid = msgid;
+
+ lr = ldap_tavl_find( ld->ld_requests, &needle, ldap_req_cmp );
+ if ( lr != NULL && lr->lr_status != LDAP_REQST_COMPLETED ) {
+ /* try_read1msg is the only user at the moment and we would free it
+ * multiple times if retrieving the request again */
+ assert( lr->lr_refcnt == 0 );
+ lr->lr_refcnt++;
+ Debug3( LDAP_DEBUG_TRACE, "ldap_find_request_by_msgid: "
+ "msgid %d, lr %p lr->lr_refcnt = %d\n",
+ msgid, lr, lr->lr_refcnt );
+ return lr;
}
- return( lr );
+ Debug2( LDAP_DEBUG_TRACE, "ldap_find_request_by_msgid: "
+ "msgid %d, lr %p\n", msgid, lr );
+ return NULL;
}
/* protected by req_mutex */
{
LDAPRequest *lr;
- for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) {
- if ( lr == lrx ) {
- if ( lr->lr_refcnt > 0 ) {
- lr->lr_refcnt--;
-
- } else if ( lr->lr_refcnt < 0 ) {
- lr->lr_refcnt++;
- if ( lr->lr_refcnt == 0 ) {
- lr = NULL;
- }
+ lr = ldap_tavl_find( ld->ld_requests, lrx, ldap_req_cmp );
+ Debug2( LDAP_DEBUG_TRACE, "ldap_return_request: "
+ "lrx %p, lr %p\n", lrx, lr );
+ if ( lr ) {
+ assert( lr == lrx );
+ if ( lr->lr_refcnt > 0 ) {
+ lr->lr_refcnt--;
+ } else if ( lr->lr_refcnt < 0 ) {
+ lr->lr_refcnt++;
+ if ( lr->lr_refcnt == 0 ) {
+ lr = NULL;
}
- break;
}
}
+ Debug3( LDAP_DEBUG_TRACE, "ldap_return_request: "
+ "lrx->lr_msgid %d, lrx->lr_refcnt is now %d, lr is %s present\n",
+ lrx->lr_msgid, lrx->lr_refcnt, lr ? "still" : "not" );
+ /* The request is not tracked anymore */
if ( lr == NULL ) {
ldap_free_request_int( ld, lrx );
-
} else if ( freeit ) {
ldap_free_request( ld, lrx );
}