X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=libraries%2Flibldap%2Fresult.c;h=b6e8e75105f89b2ac02d22bc8d00d6bc888e0fd8;hb=7d13ef7e42f1514dd99878835a13a700da4f4b69;hp=945176bf4eb12062bfbee549c10c5bd12fa83025;hpb=19d7e565f09e30e2329c78eba80df269f010b74d;p=openldap diff --git a/libraries/libldap/result.c b/libraries/libldap/result.c index 945176bf4e..b6e8e75105 100644 --- a/libraries/libldap/result.c +++ b/libraries/libldap/result.c @@ -2,7 +2,7 @@ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * - * Copyright 1998-2008 The OpenLDAP Foundation. + * Copyright 1998-2012 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -66,12 +66,12 @@ #include "ldap_log.h" #include "lutil.h" -static int ldap_abandoned LDAP_P(( LDAP *ld, ber_int_t msgid, int *idx )); -static int ldap_mark_abandoned LDAP_P(( LDAP *ld, ber_int_t msgid, int idx )); +static int ldap_abandoned LDAP_P(( LDAP *ld, ber_int_t msgid )); +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 )); static ber_tag_t try_read1msg LDAP_P(( LDAP *ld, ber_int_t msgid, - int all, LDAPConn **lc, LDAPMessage **result )); + int all, LDAPConn *lc, LDAPMessage **result )); static ber_tag_t build_result_ber LDAP_P(( LDAP *ld, BerElement **bp, LDAPRequest *lr )); static void merge_error_info LDAP_P(( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr )); static LDAPMessage * chkResponseList LDAP_P(( LDAP *ld, int msgid, int all)); @@ -106,7 +106,6 @@ ldap_result( struct timeval *timeout, LDAPMessage **result ) { - LDAPMessage *lm = NULL; int rc; assert( ld != NULL ); @@ -114,31 +113,14 @@ ldap_result( Debug( LDAP_DEBUG_TRACE, "ldap_result ld %p msgid %d\n", (void *)ld, msgid, 0 ); -#ifdef LDAP_R_COMPILE - ldap_pvt_thread_mutex_lock( &ld->ld_res_mutex ); -#endif - -#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 + LDAP_MUTEX_LOCK( &ld->ld_res_mutex ); + rc = wait4msg( ld, msgid, all, timeout, result ); + LDAP_MUTEX_UNLOCK( &ld->ld_res_mutex ); return rc; } +/* protected by res_mutex */ static LDAPMessage * chkResponseList( LDAP *ld, @@ -155,9 +137,7 @@ chkResponseList( * wait until it arrives or timeout occurs. */ -#ifdef LDAP_R_COMPILE - LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex ); -#endif + LDAP_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex ); Debug( LDAP_DEBUG_TRACE, "ldap_chkResponseList ld %p msgid %d all %d\n", @@ -165,12 +145,10 @@ chkResponseList( lastlm = &ld->ld_responses; for ( lm = ld->ld_responses; lm != NULL; lm = nextlm ) { - int idx; - nextlm = lm->lm_next; ++cnt; - if ( ldap_abandoned( ld, lm->lm_msgid, &idx ) ) { + if ( ldap_abandoned( ld, lm->lm_msgid ) ) { Debug( LDAP_DEBUG_ANY, "response list msg abandoned, " "msgid %d message type %s\n", @@ -185,7 +163,7 @@ chkResponseList( default: /* there's no need to keep the id * in the abandoned list any longer */ - ldap_mark_abandoned( ld, lm->lm_msgid, idx ); + ldap_mark_abandoned( ld, lm->lm_msgid ); break; } @@ -252,6 +230,7 @@ chkResponseList( return lm; } +/* protected by res_mutex */ static int wait4msg( LDAP *ld, @@ -270,9 +249,7 @@ wait4msg( assert( ld != NULL ); assert( result != NULL ); -#ifdef LDAP_R_COMPILE - LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex ); -#endif + LDAP_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex ); if ( timeout == NULL && ld->ld_options.ldo_tm_api.tv_sec >= 0 ) { tv = ld->ld_options.ldo_tm_api; @@ -289,7 +266,7 @@ wait4msg( } #endif /* LDAP_DEBUG */ - if ( timeout != NULL ) { + if ( timeout != NULL && timeout->tv_sec != -1 ) { tv0 = *timeout; tv = *timeout; tvp = &tv; @@ -307,18 +284,10 @@ wait4msg( if ( ldap_debug & LDAP_DEBUG_TRACE ) { Debug( LDAP_DEBUG_TRACE, "wait4msg continue ld %p msgid %d all %d\n", (void *)ld, msgid, all ); -#ifdef LDAP_R_COMPILE - ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex ); -#endif ldap_dump_connection( ld, ld->ld_conns, 1 ); -#ifdef LDAP_R_COMPILE - ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex ); - ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex ); -#endif + LDAP_MUTEX_LOCK( &ld->ld_req_mutex ); ldap_dump_requests_and_responses( ld ); -#ifdef LDAP_R_COMPILE - ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex ); -#endif + LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); } #endif /* LDAP_DEBUG */ @@ -328,44 +297,35 @@ wait4msg( } else { int lc_ready = 0; -#ifdef LDAP_R_COMPILE - ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex ); -#endif + LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) { if ( ber_sockbuf_ctrl( lc->lconn_sb, LBER_SB_OPT_DATA_READY, NULL ) ) { -#ifdef LDAP_R_COMPILE - ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex ); -#endif - rc = try_read1msg( ld, msgid, all, &lc, result ); -#ifdef LDAP_R_COMPILE - ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex ); -#endif lc_ready = 1; break; } } -#ifdef LDAP_R_COMPILE - ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex ); -#endif if ( !lc_ready ) { + int err; rc = ldap_int_select( ld, tvp ); -#ifdef LDAP_DEBUG if ( rc == -1 ) { + err = sock_errno(); +#ifdef LDAP_DEBUG Debug( LDAP_DEBUG_TRACE, "ldap_int_select returned -1: errno %d\n", - sock_errno(), 0, 0 ); - } + err, 0, 0 ); #endif + } if ( rc == 0 || ( rc == -1 && ( !LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_RESTART) - || sock_errno() != EINTR ) ) ) + || err != EINTR ) ) ) { ld->ld_errno = (rc == -1 ? LDAP_SERVER_DOWN : LDAP_TIMEOUT); + LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); return( rc ); } @@ -373,55 +333,51 @@ wait4msg( rc = LDAP_MSG_X_KEEP_LOOKING; /* select interrupted: loop */ } else { - rc = LDAP_MSG_X_KEEP_LOOKING; -#ifdef LDAP_R_COMPILE - ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex ); -#endif - if ( ld->ld_requests && - ld->ld_requests->lr_status == LDAP_REQST_WRITING && - ldap_is_write_ready( ld, - ld->ld_requests->lr_conn->lconn_sb ) ) - { - ldap_int_flush_request( ld, ld->ld_requests ); - } -#ifdef LDAP_R_COMPILE - ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex ); - ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex ); -#endif - for ( lc = ld->ld_conns; - rc == LDAP_MSG_X_KEEP_LOOKING && lc != NULL; ) + lc_ready = 1; + } + } + if ( lc_ready ) { + LDAPConn *lnext; + int serviced = 0; + rc = LDAP_MSG_X_KEEP_LOOKING; + LDAP_MUTEX_LOCK( &ld->ld_req_mutex ); + if ( ld->ld_requests && + ld->ld_requests->lr_status == LDAP_REQST_WRITING && + ldap_is_write_ready( ld, + ld->ld_requests->lr_conn->lconn_sb ) ) + { + serviced = 1; + ldap_int_flush_request( ld, ld->ld_requests ); + } + for ( lc = ld->ld_conns; + rc == LDAP_MSG_X_KEEP_LOOKING && lc != NULL; + lc = lnext ) + { + if ( lc->lconn_status == LDAP_CONNST_CONNECTED && + ldap_is_read_ready( ld, lc->lconn_sb ) ) { - if ( lc->lconn_status == LDAP_CONNST_CONNECTED && - ldap_is_read_ready( ld, lc->lconn_sb ) ) - { -#ifdef LDAP_R_COMPILE - ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex ); -#endif - rc = try_read1msg( ld, msgid, all, &lc, result ); -#ifdef LDAP_R_COMPILE - ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex ); -#endif - if ( lc == NULL ) { - /* if lc gets free()'d, - * there's no guarantee - * lc->lconn_next is still - * sane; better restart - * (ITS#4405) */ - lc = ld->ld_conns; - - /* don't get to next conn! */ - break; - } + serviced = 1; + /* Don't let it get freed out from under us */ + ++lc->lconn_refcnt; + rc = try_read1msg( ld, msgid, all, lc, result ); + lnext = lc->lconn_next; + + /* Only take locks if we're really freeing */ + if ( lc->lconn_refcnt <= 1 ) { + ldap_free_connection( ld, lc, 0, 1 ); + } else { + --lc->lconn_refcnt; } - - /* next conn */ - lc = lc->lconn_next; + } else { + lnext = lc->lconn_next; } -#ifdef LDAP_R_COMPILE - ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex ); -#endif } + LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); + /* Quit looping if no one handled any events */ + if (!serviced) + rc = -1; } + LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); } if ( rc == LDAP_MSG_X_KEEP_LOOKING && tvp != NULL ) { @@ -475,25 +431,24 @@ wait4msg( } +/* protected by res_mutex, conn_mutex and req_mutex */ static ber_tag_t try_read1msg( LDAP *ld, ber_int_t msgid, int all, - LDAPConn **lcp, + LDAPConn *lc, LDAPMessage **result ) { BerElement *ber; LDAPMessage *newmsg, *l, *prev; ber_int_t id; - int idx; ber_tag_t tag; ber_len_t len; int foundit = 0; LDAPRequest *lr, *tmplr, dummy_lr = { 0 }; - LDAPConn *lc; BerElement tmpber; - int rc, refer_cnt, hadref, simple_request; + int rc, refer_cnt, hadref, simple_request, err; ber_int_t lderr; #ifdef LDAP_CONNECTIONLESS @@ -502,18 +457,15 @@ try_read1msg( #endif assert( ld != NULL ); - assert( lcp != NULL ); - assert( *lcp != NULL ); + assert( lc != NULL ); -#ifdef LDAP_R_COMPILE - LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex ); -#endif + LDAP_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex ); + LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex ); + LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex ); Debug( LDAP_DEBUG_TRACE, "read1msg: ld %p msgid %d all %d\n", (void *)ld, msgid, all ); - lc = *lcp; - retry: if ( lc->lconn_ber == NULL ) { lc->lconn_ber = ldap_alloc_ber_with_options( ld ); @@ -547,25 +499,16 @@ nextresp3: break; case LBER_DEFAULT: + err = sock_errno(); #ifdef LDAP_DEBUG Debug( LDAP_DEBUG_CONNS, "ber_get_next failed.\n", 0, 0, 0 ); #endif -#ifdef EWOULDBLOCK - if ( sock_errno() == EWOULDBLOCK ) return LDAP_MSG_X_KEEP_LOOKING; -#endif -#ifdef EAGAIN - if ( sock_errno() == EAGAIN ) return LDAP_MSG_X_KEEP_LOOKING; -#endif + if ( err == EWOULDBLOCK ) return LDAP_MSG_X_KEEP_LOOKING; + if ( err == EAGAIN ) return LDAP_MSG_X_KEEP_LOOKING; ld->ld_errno = LDAP_SERVER_DOWN; -#ifdef LDAP_R_COMPILE - ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex ); -#endif - ldap_free_connection( ld, lc, 1, 0 ); -#ifdef LDAP_R_COMPILE - ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex ); -#endif - lc = *lcp = NULL; + --lc->lconn_refcnt; + lc->lconn_status = 0; return -1; default: @@ -589,7 +532,7 @@ nextresp3: /* if it's been abandoned, toss it */ if ( id > 0 ) { - if ( ldap_abandoned( ld, id, &idx ) ) { + if ( ldap_abandoned( ld, id ) ) { /* the message type */ tag = ber_peek_tag( ber, &len ); switch ( tag ) { @@ -602,7 +545,7 @@ nextresp3: default: /* there's no need to keep the id * in the abandoned list any longer */ - ldap_mark_abandoned( ld, id, idx ); + ldap_mark_abandoned( ld, id ); break; } @@ -645,6 +588,7 @@ retry_ber: ber_scanf(ber, "x{"); } nextresp2: + ; #endif } @@ -764,8 +708,9 @@ nextresp2: } /* Do we need to check for referrals? */ - if ( LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_REFERRALS) || - lr->lr_parent != NULL ) + if ( tag != LDAP_RES_BIND && + ( LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_REFERRALS) || + lr->lr_parent != NULL )) { char **refs = NULL; ber_len_t len; @@ -862,6 +807,10 @@ nextresp2: return( -1 ); /* fatal error */ } lr->lr_res_errno = LDAP_SUCCESS; /* sucessfully chased referral */ + if ( lr->lr_res_matched ) { + LDAP_FREE( lr->lr_res_matched ); + lr->lr_res_matched = NULL; + } } else { if ( lr->lr_outrefcnt <= 0 && lr->lr_parent == NULL ) { @@ -878,6 +827,7 @@ nextresp2: Debug( LDAP_DEBUG_TRACE, "read1msg: mark request completed, ld %p msgid %d\n", (void *)ld, lr->lr_msgid, 0); + tmplr = lr; while ( lr->lr_parent != NULL ) { merge_error_info( ld, lr->lr_parent, lr ); @@ -886,6 +836,12 @@ nextresp2: break; /* not completely done yet */ } } + /* ITS#6744: Original lr was refcounted when we retrieved it, + * must release it now that we're working with the parent + */ + if ( tmplr->lr_parent ) { + ldap_return_request( ld, tmplr, 0 ); + } /* Check if all requests are finished, lr is now parent */ tmplr = lr; @@ -930,18 +886,12 @@ nextresp2: } /* - * RF 4511 unsolicited (id == 0) responses + * RFC 4511 unsolicited (id == 0) responses * shouldn't necessarily end the connection */ if ( lc != NULL && id != 0 ) { -#ifdef LDAP_R_COMPILE - ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex ); -#endif - ldap_free_connection( ld, lc, 0, 1 ); -#ifdef LDAP_R_COMPILE - ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex ); -#endif - lc = *lcp = NULL; + --lc->lconn_refcnt; + lc = NULL; } } } @@ -1007,18 +957,12 @@ nextresp2: /* get rid of the connection... */ if ( lc != NULL ) { -#ifdef LDAP_R_COMPILE - ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex ); -#endif - ldap_free_connection( ld, lc, 0, 1 ); -#ifdef LDAP_R_COMPILE - ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex ); -#endif - lc = *lcp = NULL; + --lc->lconn_refcnt; } /* need to return -1, because otherwise * a valid result is expected */ + ld->ld_errno = lderr; return -1; } } @@ -1123,7 +1067,8 @@ nextresp2: if ( msgid == LDAP_RES_ANY || id == msgid ) { if ( all == LDAP_MSG_ONE || ( newmsg->lm_msgtype != LDAP_RES_SEARCH_RESULT - && newmsg->lm_msgtype != LDAP_RES_SEARCH_ENTRY + && newmsg->lm_msgtype != LDAP_RES_SEARCH_ENTRY + && newmsg->lm_msgtype != LDAP_RES_INTERMEDIATE && newmsg->lm_msgtype != LDAP_RES_SEARCH_REFERENCE ) ) { *result = newmsg; @@ -1354,9 +1299,7 @@ ldap_msgdelete( LDAP *ld, int msgid ) Debug( LDAP_DEBUG_TRACE, "ldap_msgdelete ld=%p msgid=%d\n", (void *)ld, msgid, 0 ); -#ifdef LDAP_R_COMPILE - ldap_pvt_thread_mutex_lock( &ld->ld_res_mutex ); -#endif + LDAP_MUTEX_LOCK( &ld->ld_res_mutex ); prev = NULL; for ( lm = ld->ld_responses; lm != NULL; lm = lm->lm_next ) { if ( lm->lm_msgid == msgid ) { @@ -1375,9 +1318,7 @@ ldap_msgdelete( LDAP *ld, int msgid ) prev->lm_next = lm->lm_next; } } -#ifdef LDAP_R_COMPILE - ldap_pvt_thread_mutex_unlock( &ld->ld_res_mutex ); -#endif + LDAP_MUTEX_UNLOCK( &ld->ld_res_mutex ); if ( lm ) { switch ( ldap_msgfree( lm ) ) { case LDAP_RES_SEARCH_ENTRY: @@ -1400,40 +1341,37 @@ ldap_msgdelete( LDAP *ld, int msgid ) * * 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, int *idxp ) +ldap_abandoned( LDAP *ld, ber_int_t msgid ) { -#ifdef LDAP_R_COMPILE - LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex ); -#endif - - assert( idxp != NULL ); + int ret, idx; assert( msgid >= 0 ); - assert( ld->ld_nabandoned >= 0 ); - return ldap_int_bisect_find( ld->ld_abandoned, ld->ld_nabandoned, msgid, idxp ); + LDAP_MUTEX_LOCK( &ld->ld_abandon_mutex ); + ret = ldap_int_bisect_find( ld->ld_abandoned, ld->ld_nabandoned, msgid, &idx ); + LDAP_MUTEX_UNLOCK( &ld->ld_abandon_mutex ); + return ret; } /* * ldap_mark_abandoned - * - * expects ld_res_mutex to be locked */ static int -ldap_mark_abandoned( LDAP *ld, ber_int_t msgid, int idx ) +ldap_mark_abandoned( LDAP *ld, ber_int_t msgid ) { -#ifdef LDAP_R_COMPILE - LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex ); -#endif - - /* NOTE: those assertions are repeated in ldap_int_bisect_delete() */ - assert( idx >= 0 ); - assert( idx < ld->ld_nabandoned ); - assert( ld->ld_abandoned[ idx ] == msgid ); + int ret, idx; - return ldap_int_bisect_delete( &ld->ld_abandoned, &ld->ld_nabandoned, + assert( msgid >= 0 ); + LDAP_MUTEX_LOCK( &ld->ld_abandon_mutex ); + ret = ldap_int_bisect_find( ld->ld_abandoned, ld->ld_nabandoned, msgid, &idx ); + if (ret <= 0) { /* error or already deleted by another thread */ + LDAP_MUTEX_UNLOCK( &ld->ld_abandon_mutex ); + return ret; + } + /* still in abandoned array, so delete */ + ret = ldap_int_bisect_delete( &ld->ld_abandoned, &ld->ld_nabandoned, msgid, idx ); + LDAP_MUTEX_UNLOCK( &ld->ld_abandon_mutex ); + return ret; }