X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=libraries%2Flibldap%2Frequest.c;h=6098f0c904b14c48389c189c55252c6f0ff78dc2;hb=e22dc83ac096d1239a6903199f5dc3231b0f444b;hp=14a2515e9e3e6c9a3bb9ba9669ef1ed32aff9852;hpb=86b566f029a6df460a0cbfe89074696acebd4624;p=openldap diff --git a/libraries/libldap/request.c b/libraries/libldap/request.c index 14a2515e9e..6098f0c904 100644 --- a/libraries/libldap/request.c +++ b/libraries/libldap/request.c @@ -1,7 +1,7 @@ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * - * Copyright 1998-2006 The OpenLDAP Foundation. + * Copyright 1998-2009 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -150,7 +150,7 @@ ldap_int_flush_request( LDAPConn *lc = lr->lr_conn; if ( ber_flush2( lc->lconn_sb, lr->lr_ber, LBER_FLUSH_FREE_NEVER ) != 0 ) { - if ( errno == EAGAIN ) { + if ( sock_errno() == EAGAIN ) { /* need to continue write later */ lr->lr_status = LDAP_REQST_WRITING; ldap_mark_select_write( ld, lc->lconn_sb ); @@ -209,11 +209,43 @@ ldap_send_server_request( } } + /* async connect... */ + if ( lc != NULL && lc->lconn_status == LDAP_CONNST_CONNECTING ) { + ber_socket_t sd = AC_SOCKET_ERROR; + struct timeval tv = { 0 }; + + ber_sockbuf_ctrl( lc->lconn_sb, LBER_SB_OPT_GET_FD, &sd ); + + /* poll ... */ + switch ( ldap_int_poll( ld, sd, &tv ) ) { + case 0: + /* go on! */ + lc->lconn_status = LDAP_CONNST_CONNECTED; + break; + + case -2: + /* async only occurs if a network timeout is set */ + + /* honor network timeout */ + if ( time( NULL ) - lc->lconn_created <= ld->ld_options.ldo_tm_net.tv_sec ) + { + /* caller will have to call again */ + ld->ld_errno = LDAP_X_CONNECTING; + } + /* fallthru */ + + default: + /* error */ + break; + } + } + if ( lc == NULL || lc->lconn_status != LDAP_CONNST_CONNECTED ) { - ber_free( ber, 1 ); if ( ld->ld_errno == LDAP_SUCCESS ) { ld->ld_errno = LDAP_SERVER_DOWN; } + + ber_free( ber, 1 ); if ( incparent ) { /* Forget about the bind */ --parentreq->lr_outrefcnt; @@ -223,6 +255,19 @@ ldap_send_server_request( use_connection( ld, lc ); +#ifdef LDAP_CONNECTIONLESS + if ( LDAP_IS_UDP( ld )) { + BerElement tmpber = *ber; + ber_rewind( &tmpber ); + rc = ber_write( &tmpber, ld->ld_options.ldo_peer, + sizeof( struct sockaddr ), 0 ); + if ( rc == -1 ) { + ld->ld_errno = LDAP_ENCODING_ERROR; + return rc; + } + } +#endif + /* If we still have an incomplete write, try to finish it before * dealing with the new request. If we don't finish here, return * LDAP_BUSY and let the caller retry later. We only allow a single @@ -293,7 +338,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; @@ -306,11 +352,38 @@ ldap_send_server_request( return( msgid ); } +/* return 0 if no StartTLS ext, 1 if present, 2 if critical */ +static int +find_tls_ext( LDAPURLDesc *srv ) +{ + int i, crit; + char *ext; + + if ( !srv->lud_exts ) + return 0; + + for (i=0; srv->lud_exts[i]; i++) { + crit = 0; + ext = srv->lud_exts[i]; + if ( ext[0] == '!') { + ext++; + crit = 1; + } + if ( !strcasecmp( ext, "StartTLS" ) || + !strcasecmp( ext, "X-StartTLS" ) || + !strcmp( ext, LDAP_EXOP_START_TLS )) { + return crit + 1; + } + } + return 0; +} + LDAPConn * ldap_new_connection( LDAP *ld, LDAPURLDesc **srvlist, int use_ldsb, int connect, LDAPreqinfo *bind ) { LDAPConn *lc; + int async = 0; Debug( LDAP_DEBUG_TRACE, "ldap_new_connection %d %d %d\n", use_ldsb, connect, (bind != NULL) ); @@ -340,12 +413,16 @@ ldap_new_connection( LDAP *ld, LDAPURLDesc **srvlist, int use_ldsb, if ( connect ) { LDAPURLDesc **srvp, *srv = NULL; + async = LDAP_BOOL_GET( &ld->ld_options, LDAP_BOOL_CONNECT_ASYNC ); + for ( srvp = srvlist; *srvp != NULL; srvp = &(*srvp)->lud_next ) { - if ( ldap_int_open_connection( ld, lc, *srvp, 0 ) != -1 ) - { + int rc; + + rc = ldap_int_open_connection( ld, lc, *srvp, async ); + if ( rc != -1 ) { srv = *srvp; - if ( ld->ld_urllist_proc ) { + if ( ld->ld_urllist_proc && ( !async || rc != -2 ) ) { ld->ld_urllist_proc( ld, srvlist, srvp, ld->ld_urllist_params ); } @@ -365,7 +442,7 @@ ldap_new_connection( LDAP *ld, LDAPURLDesc **srvlist, int use_ldsb, lc->lconn_server = ldap_url_dup( srv ); } - lc->lconn_status = LDAP_CONNST_CONNECTED; + lc->lconn_status = async ? LDAP_CONNST_CONNECTING : LDAP_CONNST_CONNECTED; #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex ); #endif @@ -375,6 +452,38 @@ ldap_new_connection( LDAP *ld, LDAPURLDesc **srvlist, int use_ldsb, ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex ); #endif + if ( connect ) { +#ifdef HAVE_TLS + if ( lc->lconn_server->lud_exts ) { + int rc, ext = find_tls_ext( lc->lconn_server ); + if ( ext ) { + LDAPConn *savedefconn; + + savedefconn = ld->ld_defconn; + ++lc->lconn_refcnt; /* avoid premature free */ + ld->ld_defconn = lc; + +#ifdef LDAP_R_COMPILE + ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex ); + ldap_pvt_thread_mutex_unlock( &ld->ld_res_mutex ); +#endif + rc = ldap_start_tls_s( ld, NULL, NULL ); +#ifdef LDAP_R_COMPILE + ldap_pvt_thread_mutex_lock( &ld->ld_res_mutex ); + ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex ); +#endif + ld->ld_defconn = savedefconn; + --lc->lconn_refcnt; + + if ( rc != LDAP_SUCCESS && ext == 2 ) { + ldap_free_connection( ld, lc, 1, 0 ); + return NULL; + } + } + } +#endif + } + if ( bind != NULL ) { int err = 0; LDAPConn *savedefconn; @@ -420,6 +529,7 @@ ldap_new_connection( LDAP *ld, LDAPURLDesc **srvlist, int use_ldsb, } ldap_free_urldesc( srvfunc ); } + } else { int msgid, rc; struct berval passwd = BER_BVNULL; @@ -428,7 +538,10 @@ ldap_new_connection( LDAP *ld, LDAPURLDesc **srvlist, int use_ldsb, ++lc->lconn_refcnt; /* avoid premature free */ ld->ld_defconn = lc; - Debug( LDAP_DEBUG_TRACE, "anonymous rebind via ldap_bind_s\n", 0, 0, 0); + Debug( LDAP_DEBUG_TRACE, + "anonymous rebind via ldap_sasl_bind(\"\")\n", + 0, 0, 0); + #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex ); ldap_pvt_thread_mutex_unlock( &ld->ld_res_mutex ); @@ -466,7 +579,13 @@ ldap_new_connection( LDAP *ld, LDAPURLDesc **srvlist, int use_ldsb, break; default: - assert( 0 ); + Debug( LDAP_DEBUG_TRACE, + "ldap_new_connection %p: " + "unexpected response %d " + "from BIND request id=%d\n", + (void *) ld, ldap_msgtype( res ), msgid ); + err = -1; + break; } } } @@ -516,8 +635,7 @@ find_connection( LDAP *ld, LDAPURLDesc *srv, int any ) if ( lsu_port == lcu_port && strcmp( lcu->lud_scheme, lsu->lud_scheme ) == 0 - && lcu->lud_host != NULL && *lcu->lud_host != '\0' - && lsu->lud_host != NULL && *lsu->lud_host != '\0' + && lcu->lud_host != NULL && lsu->lud_host != NULL && strcasecmp( lsu->lud_host, lcu->lud_host ) == 0 ) { found = 1; @@ -570,6 +688,9 @@ ldap_free_connection( LDAP *ld, LDAPConn *lc, int force, int unbind ) } else { prevlc->lconn_next = tmplc->lconn_next; } + if ( ld->ld_defconn == lc ) { + ld->ld_defconn = NULL; + } break; } prevlc = tmplc; @@ -578,6 +699,28 @@ ldap_free_connection( LDAP *ld, LDAPConn *lc, int force, int unbind ) ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex ); #endif + /* process connection callbacks */ + { + struct ldapoptions *lo; + ldaplist *ll; + ldap_conncb *cb; + + lo = &ld->ld_options; + if ( lo->ldo_conn_cbs ) { + for ( ll=lo->ldo_conn_cbs; ll; ll=ll->ll_next ) { + cb = ll->ll_data; + cb->lc_del( ld, lc->lconn_sb, cb ); + } + } + lo = LDAP_INT_GLOBAL_OPT(); + if ( lo->ldo_conn_cbs ) { + for ( ll=lo->ldo_conn_cbs; ll; ll=ll->ll_next ) { + cb = ll->ll_data; + cb->lc_del( ld, lc->lconn_sb, cb ); + } + } + } + if ( lc->lconn_status == LDAP_CONNST_CONNECTED ) { ldap_mark_select_clear( ld, lc->lconn_sb ); if ( unbind ) { @@ -591,15 +734,16 @@ ldap_free_connection( LDAP *ld, LDAPConn *lc, int force, int unbind ) } ldap_int_sasl_close( ld, lc ); +#ifdef HAVE_GSSAPI + ldap_int_gssapi_close( ld, lc ); +#endif ldap_free_urllist( lc->lconn_server ); -#ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND - if ( lc->lconn_krbinstance != NULL ) { - LDAP_FREE( lc->lconn_krbinstance ); - } -#endif - /* FIXME: is this at all possible? */ + /* 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 */ if ( force ) { LDAPRequest *lr; @@ -616,6 +760,8 @@ ldap_free_connection( LDAP *ld, LDAPConn *lc, int force, int unbind ) if ( lc->lconn_sb != ld->ld_sb ) { ber_sockbuf_free( lc->lconn_sb ); + } else { + ber_int_sb_close( lc->lconn_sb ); } if ( lc->lconn_rebind_queue != NULL) { @@ -647,37 +793,39 @@ ldap_dump_connection( LDAP *ld, LDAPConn *lconns, int all ) LDAPConn *lc; char timebuf[32]; - fprintf( stderr, "** ld %p Connection%s:\n", (void *)ld, all ? "s" : "" ); + Debug( LDAP_DEBUG_TRACE, "** ld %p Connection%s:\n", (void *)ld, all ? "s" : "", 0 ); for ( lc = lconns; lc != NULL; lc = lc->lconn_next ) { if ( lc->lconn_server != NULL ) { - fprintf( stderr, "* host: %s port: %d%s\n", + Debug( LDAP_DEBUG_TRACE, "* host: %s port: %d%s\n", ( lc->lconn_server->lud_host == NULL ) ? "(null)" : lc->lconn_server->lud_host, lc->lconn_server->lud_port, ( lc->lconn_sb == ld->ld_sb ) ? " (default)" : "" ); } - fprintf( stderr, " refcnt: %d status: %s\n", lc->lconn_refcnt, - ( lc->lconn_status == LDAP_CONNST_NEEDSOCKET ) ? - "NeedSocket" : ( lc->lconn_status == - LDAP_CONNST_CONNECTING ) ? "Connecting" : "Connected" ); - fprintf( stderr, " last used: %s", - ldap_pvt_ctime( &lc->lconn_lastused, timebuf )); - if( lc->lconn_rebind_inprogress ) { - fprintf( stderr, " rebind in progress\n"); - if( lc->lconn_rebind_queue != NULL) { - int i = 0; - for( ;lc->lconn_rebind_queue[i] != NULL; i++) { - int j = 0; - for( ;lc->lconn_rebind_queue[i][j] != 0; j++) { - fprintf( stderr, " queue %d entry %d - %s\n", - i, j, lc->lconn_rebind_queue[i][j]); + Debug( LDAP_DEBUG_TRACE, " refcnt: %d status: %s\n", lc->lconn_refcnt, + ( lc->lconn_status == LDAP_CONNST_NEEDSOCKET ) + ? "NeedSocket" : + ( lc->lconn_status == LDAP_CONNST_CONNECTING ) + ? "Connecting" : "Connected", 0 ); + Debug( LDAP_DEBUG_TRACE, " last used: %s%s\n", + ldap_pvt_ctime( &lc->lconn_lastused, timebuf ), + lc->lconn_rebind_inprogress ? " rebind in progress" : "", 0 ); + if ( lc->lconn_rebind_inprogress ) { + if ( lc->lconn_rebind_queue != NULL) { + int i; + + for ( i = 0; lc->lconn_rebind_queue[i] != NULL; i++ ) { + int j; + for( j = 0; lc->lconn_rebind_queue[i][j] != 0; j++ ) { + Debug( LDAP_DEBUG_TRACE, " queue %d entry %d - %s\n", + i, j, lc->lconn_rebind_queue[i][j] ); } } } else { - fprintf( stderr, " queue is empty\n"); + Debug( LDAP_DEBUG_TRACE, " queue is empty\n", 0, 0, 0 ); } } - fprintf(stderr, "\n"); + Debug( LDAP_DEBUG_TRACE, "\n", 0, 0, 0 ); if ( !all ) { break; } @@ -690,56 +838,66 @@ ldap_dump_requests_and_responses( LDAP *ld ) { LDAPRequest *lr; LDAPMessage *lm, *l; + int i; -#ifdef LDAP_R_COMPILE - ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex ); -#endif - fprintf( stderr, "** ld %p Outstanding Requests:\n", (void *)ld ); - if (( lr = ld->ld_requests ) == NULL ) { - fprintf( stderr, " Empty\n" ); + Debug( LDAP_DEBUG_TRACE, "** ld %p Outstanding Requests:\n", + (void *)ld, 0, 0 ); + lr = ld->ld_requests; + if ( lr == NULL ) { + Debug( LDAP_DEBUG_TRACE, " Empty\n", 0, 0, 0 ); } - for ( ; lr != NULL; lr = lr->lr_next ) { - fprintf( stderr, " * msgid %d, origid %d, status %s\n", + for ( i = 0; lr != NULL; lr = lr->lr_next, i++ ) { + Debug( LDAP_DEBUG_TRACE, " * msgid %d, origid %d, status %s\n", lr->lr_msgid, lr->lr_origid, ( lr->lr_status == LDAP_REQST_INPROGRESS ) ? "InProgress" : ( lr->lr_status == LDAP_REQST_CHASINGREFS ) ? "ChasingRefs" : ( lr->lr_status == LDAP_REQST_NOTCONNECTED ) ? "NotConnected" : ( lr->lr_status == LDAP_REQST_WRITING ) ? "Writing" : ( lr->lr_status == LDAP_REQST_COMPLETED ) ? "RequestCompleted" - : "InvalidStatus"); - fprintf( stderr, " outstanding referrals %d, parent count %d\n", - lr->lr_outrefcnt, lr->lr_parentcnt ); + : "InvalidStatus" ); + Debug( LDAP_DEBUG_TRACE, " outstanding referrals %d, parent count %d\n", + lr->lr_outrefcnt, lr->lr_parentcnt, 0 ); } -#ifdef LDAP_R_COMPILE - ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex ); -#endif - fprintf( stderr, "** ld %p Response Queue:\n", (void *)ld ); + Debug( LDAP_DEBUG_TRACE, " ld %p request count %d (abandoned %lu)\n", + (void *)ld, i, ld->ld_nabandoned ); + Debug( LDAP_DEBUG_TRACE, "** ld %p Response Queue:\n", (void *)ld, 0, 0 ); if ( ( lm = ld->ld_responses ) == NULL ) { - fprintf( stderr, " Empty\n" ); + Debug( LDAP_DEBUG_TRACE, " Empty\n", 0, 0, 0 ); } - for ( ; lm != NULL; lm = lm->lm_next ) { - fprintf( stderr, " * msgid %d, type %lu\n", - lm->lm_msgid, (unsigned long) lm->lm_msgtype ); - if ( ( l = lm->lm_chain ) != NULL ) { - fprintf( stderr, " chained responses:\n" ); - for ( ; l != NULL; l = l->lm_chain ) { - fprintf( stderr, + for ( i = 0; lm != NULL; lm = lm->lm_next, i++ ) { + Debug( LDAP_DEBUG_TRACE, " * msgid %d, type %lu\n", + lm->lm_msgid, (unsigned long)lm->lm_msgtype, 0 ); + if ( lm->lm_chain != NULL ) { + Debug( LDAP_DEBUG_TRACE, " chained responses:\n", 0, 0, 0 ); + for ( l = lm->lm_chain; l != NULL; l = l->lm_chain ) { + Debug( LDAP_DEBUG_TRACE, " * msgid %d, type %lu\n", l->lm_msgid, - (unsigned long) l->lm_msgtype ); + (unsigned long)l->lm_msgtype, 0 ); } } } + Debug( LDAP_DEBUG_TRACE, " ld %p response count %d\n", (void *)ld, i, 0 ); } #endif /* LDAP_DEBUG */ 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; @@ -749,6 +907,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; @@ -770,7 +937,6 @@ ldap_free_request_int( LDAP *ld, LDAPRequest *lr ) void ldap_free_request( LDAP *ld, LDAPRequest *lr ) { - LDAPRequest **ttmplr; #ifdef LDAP_R_COMPILE LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex ); #endif @@ -779,14 +945,21 @@ ldap_free_request( LDAP *ld, LDAPRequest *lr ) lr->lr_origid, lr->lr_msgid, 0 ); /* free all referrals (child requests) */ - while ( lr->lr_child ) + while ( lr->lr_child ) { ldap_free_request( ld, lr->lr_child ); + } if ( lr->lr_parent != NULL ) { + LDAPRequest **lrp; + --lr->lr_parent->lr_outrefcnt; - for ( ttmplr = &lr->lr_parent->lr_child; *ttmplr && *ttmplr != lr; ttmplr = &(*ttmplr)->lr_refnext ); - if ( *ttmplr == lr ) - *ttmplr = lr->lr_refnext; + for ( lrp = &lr->lr_parent->lr_child; + *lrp && *lrp != lr; + lrp = &(*lrp)->lr_refnext ); + + if ( *lrp == lr ) { + *lrp = lr->lr_refnext; + } } ldap_free_request_int( ld, lr ); } @@ -905,10 +1078,18 @@ ldap_chase_v3referrals( LDAP *ld, LDAPRequest *lr, char **refs, int sref, char * } if( srv->lud_crit_exts ) { - /* we do not support any extensions */ - ld->ld_errno = LDAP_NOT_SUPPORTED; - rc = -1; - goto done; + int ok = 0; +#ifdef HAVE_TLS + /* If StartTLS is the only critical ext, OK. */ + if ( find_tls_ext( srv ) == 2 && srv->lud_crit_exts == 1 ) + ok = 1; +#endif + if ( !ok ) { + /* we do not support any other extensions */ + ld->ld_errno = LDAP_NOT_SUPPORTED; + rc = -1; + goto done; + } } /* check connection for re-bind in progress */ @@ -916,7 +1097,7 @@ ldap_chase_v3referrals( LDAP *ld, LDAPRequest *lr, char **refs, int sref, char * /* See if we've already requested this DN with this conn */ LDAPRequest *lp; int looped = 0; - int len = srv->lud_dn ? strlen( srv->lud_dn ) : 0; + ber_len_t len = srv->lud_dn ? strlen( srv->lud_dn ) : 0; for ( lp = origreq; lp; ) { if ( lp->lr_conn == lc && len == lp->lr_dn.bv_len @@ -929,7 +1110,7 @@ ldap_chase_v3referrals( LDAP *ld, LDAPRequest *lr, char **refs, int sref, char * if ( lp == origreq ) { lp = lp->lr_child; } else { - lp = lr->lr_refnext; + lp = lp->lr_refnext; } } if ( looped ) { @@ -1175,7 +1356,7 @@ ldap_chase_referrals( LDAP *ld, if (( lc = find_connection( ld, srv, 1 )) != NULL ) { LDAPRequest *lp; int looped = 0; - int len = srv->lud_dn ? strlen( srv->lud_dn ) : 0; + ber_len_t len = srv->lud_dn ? strlen( srv->lud_dn ) : 0; for ( lp = lr; lp; lp = lp->lr_parent ) { if ( lp->lr_conn == lc && len == lp->lr_dn.bv_len ) @@ -1187,7 +1368,7 @@ ldap_chase_referrals( LDAP *ld, } } if ( looped ) { - ldap_free_urllist(srv); + ldap_free_urllist( srv ); ld->ld_errno = LDAP_CLIENT_LOOP; rc = -1; continue; @@ -1418,6 +1599,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; } } @@ -1428,4 +1610,35 @@ ldap_find_request_by_msgid( LDAP *ld, ber_int_t msgid ) return( lr ); } +void +ldap_return_request( 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 +}