* structure used to track outstanding requests
*/
typedef struct ldapreq {
- ber_int_t lr_msgid; /* the message id */
+ ber_int_t lr_msgid; /* the message id */
int lr_status; /* status of request */
#define LDAP_REQST_COMPLETED 0
#define LDAP_REQST_INPROGRESS 1
#define LDAP_REQST_CHASINGREFS 2
#define LDAP_REQST_NOTCONNECTED 3
#define LDAP_REQST_WRITING 4
+ int lr_refcnt; /* count of references */
int lr_outrefcnt; /* count of outstanding referrals */
- ber_int_t lr_origid; /* original request's message id */
+ ber_int_t lr_origid; /* original request's message id */
int lr_parentcnt; /* count of parent requests */
- ber_tag_t lr_res_msgtype; /* result message type */
- ber_int_t lr_res_errno; /* result LDAP errno */
+ ber_tag_t lr_res_msgtype; /* result message type */
+ ber_int_t lr_res_errno; /* result LDAP errno */
char *lr_res_error; /* result error string */
char *lr_res_matched;/* result matched DN string */
BerElement *lr_ber; /* ber encoded request contents */
LDAPConn *lr_conn; /* connection used to send request */
- struct berval lr_dn; /* DN of request, in lr_ber */
+ struct berval lr_dn; /* DN of request, in lr_ber */
struct ldapreq *lr_parent; /* request that spawned this referral */
struct ldapreq *lr_child; /* first child request */
struct ldapreq *lr_refnext; /* next referral spawned */
LDAP_F (int) ldap_send_server_request( LDAP *ld, BerElement *ber, ber_int_t msgid, LDAPRequest *parentreq, LDAPURLDesc **srvlist, LDAPConn *lc, LDAPreqinfo *bind );
LDAP_F (LDAPConn *) ldap_new_connection( LDAP *ld, LDAPURLDesc **srvlist, int use_ldsb, int connect, LDAPreqinfo *bind );
LDAP_F (LDAPRequest *) ldap_find_request_by_msgid( LDAP *ld, ber_int_t msgid );
+LDAP_F (void) ldap_return_request_by_msgid( LDAP *ld, LDAPRequest *lr, int freeit );
LDAP_F (void) ldap_free_request( LDAP *ld, LDAPRequest *lr );
LDAP_F (void) ldap_free_connection( LDAP *ld, LDAPConn *lc, int force, int unbind );
LDAP_F (void) ldap_dump_connection( LDAP *ld, LDAPConn *lconns, int all );
}
lr->lr_prev = NULL;
- if (( lr->lr_next = ld->ld_requests ) != NULL ) {
+ lr->lr_next = ld->ld_requests;
+ if ( lr->lr_next != NULL ) {
lr->lr_next->lr_prev = lr;
}
ld->ld_requests = lr;
static void
ldap_free_request_int( LDAP *ld, LDAPRequest *lr )
{
+ /* 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 ) {
- /* free'ing the first request? */
- assert( ld->ld_requests == lr );
- ld->ld_requests = lr->lr_next;
+ 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;
lr->lr_next->lr_prev = lr->lr_prev;
}
+ if ( lr->lr_refcnt > 0 ) {
+ lr->lr_refcnt = -lr->lr_refcnt;
+
+ lr->lr_prev = NULL;
+ lr->lr_next = NULL;
+
+ return;
+ }
+
if ( lr->lr_ber != NULL ) {
ber_free( lr->lr_ber, 1 );
lr->lr_ber = NULL;
if ( lr->lr_parent != NULL ) {
--lr->lr_parent->lr_outrefcnt;
- for ( ttmplr = &lr->lr_parent->lr_child; *ttmplr && *ttmplr != lr; ttmplr = &(*ttmplr)->lr_refnext );
- if ( *ttmplr == lr )
+ for ( ttmplr = &lr->lr_parent->lr_child;
+ *ttmplr && *ttmplr != lr;
+ ttmplr = &(*ttmplr)->lr_refnext );
+ if ( *ttmplr == lr )
*ttmplr = lr->lr_refnext;
}
ldap_free_request_int( ld, lr );
continue; /* Skip completed requests */
}
if ( msgid == lr->lr_msgid ) {
+ lr->lr_refcnt++;
break;
}
}
return( lr );
}
+void
+ldap_return_request_by_msgid( LDAP *ld, LDAPRequest *lrx, int freeit )
+{
+ LDAPRequest *lr;
+#ifdef LDAP_R_COMPILE
+ ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
+#endif
+ 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;
+ }
+ }
+ break;
+ }
+ }
+ if ( lr == NULL ) {
+ ldap_free_request_int( ld, lrx );
+
+ } else if ( freeit ) {
+ ldap_free_request( ld, lrx );
+ }
+#ifdef LDAP_R_COMPILE
+ ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
+#endif
+}
if ( rc == -1 ) {
rc = LDAP_MSG_X_KEEP_LOOKING; /* select interrupted: loop */
+
} else {
rc = LDAP_MSG_X_KEEP_LOOKING;
#ifdef LDAP_R_COMPILE
/* 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,
}
}
}
+
} 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
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 )
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_by_msgid( 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;
+ for ( tmplr = lr->lr_child;
tmplr != NULL;
- tmplr=tmplr->lr_refnext)
+ tmplr = tmplr->lr_refnext )
{
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_by_msgid( ld, lr, 1 );
+ lr = NULL;
}
if ( lc != NULL ) {
}
}
+ if ( lr != NULL ) {
+ ldap_return_request_by_msgid( ld, lr, 0 );
+ lr = NULL;
+ }
+
if ( ber == NULL ) {
return( rc );
}