From b45c0c881d03f5df51ec6226e4e00c2d38ddc884 Mon Sep 17 00:00:00 2001 From: Pierangelo Masarati Date: Fri, 1 Sep 2006 14:00:58 +0000 Subject: [PATCH] keep count of requests in use --- libraries/libldap/ldap-int.h | 12 ++++--- libraries/libldap/request.c | 66 ++++++++++++++++++++++++++++++++---- libraries/libldap/result.c | 41 +++++++++++++--------- 3 files changed, 92 insertions(+), 27 deletions(-) diff --git a/libraries/libldap/ldap-int.h b/libraries/libldap/ldap-int.h index 9863b32b60..2276ac6e54 100644 --- a/libraries/libldap/ldap-int.h +++ b/libraries/libldap/ldap-int.h @@ -263,23 +263,24 @@ typedef struct ldap_conn { * 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 */ @@ -532,6 +533,7 @@ LDAP_F (void) ldap_set_ber_options( LDAP *ld, BerElement *ber ); 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 ); diff --git a/libraries/libldap/request.c b/libraries/libldap/request.c index c140dc73b9..6e923158ff 100644 --- a/libraries/libldap/request.c +++ b/libraries/libldap/request.c @@ -293,7 +293,8 @@ ldap_send_server_request( } 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; @@ -740,10 +741,20 @@ ldap_dump_requests_and_responses( LDAP *ld ) 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; @@ -753,6 +764,15 @@ ldap_free_request_int( LDAP *ld, LDAPRequest *lr ) 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; @@ -788,8 +808,10 @@ ldap_free_request( LDAP *ld, LDAPRequest *lr ) 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 ); @@ -1422,6 +1444,7 @@ ldap_find_request_by_msgid( LDAP *ld, ber_int_t msgid ) continue; /* Skip completed requests */ } if ( msgid == lr->lr_msgid ) { + lr->lr_refcnt++; break; } } @@ -1432,4 +1455,35 @@ ldap_find_request_by_msgid( LDAP *ld, ber_int_t msgid ) 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 +} diff --git a/libraries/libldap/result.c b/libraries/libldap/result.c index 1226e19316..b9d1e03732 100644 --- a/libraries/libldap/result.c +++ b/libraries/libldap/result.c @@ -337,6 +337,7 @@ wait4msg( if ( rc == -1 ) { rc = LDAP_MSG_X_KEEP_LOOKING; /* select interrupted: loop */ + } else { rc = LDAP_MSG_X_KEEP_LOOKING; #ifdef LDAP_R_COMPILE @@ -577,6 +578,7 @@ nextresp2: /* 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, @@ -598,6 +600,7 @@ nextresp2: } } } + } else { /* Check for V3 referral */ ber_len_t len; @@ -608,14 +611,12 @@ nextresp2: != 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; } @@ -637,6 +638,7 @@ nextresp2: 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 @@ -659,6 +661,7 @@ nextresp2: 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; @@ -690,6 +693,7 @@ nextresp2: */ 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 ) @@ -733,8 +737,10 @@ nextresp2: 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; } @@ -762,13 +768,16 @@ nextresp2: 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 ); @@ -791,9 +800,9 @@ nextresp2: /* 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; } @@ -821,13 +830,8 @@ lr->lr_res_matched ? lr->lr_res_matched : "" ); } } -#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 ) { @@ -843,6 +847,11 @@ lr->lr_res_matched ? lr->lr_res_matched : "" ); } } + if ( lr != NULL ) { + ldap_return_request_by_msgid( ld, lr, 0 ); + lr = NULL; + } + if ( ber == NULL ) { return( rc ); } -- 2.39.5