X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=libraries%2Flibldap%2Fresult.c;h=b6e8e75105f89b2ac02d22bc8d00d6bc888e0fd8;hb=7d13ef7e42f1514dd99878835a13a700da4f4b69;hp=29c0b6f55e9e8afcb4c1eeecc3caa718dad1b11e;hpb=0b660dc9f605b4a07cd1f5e6bf941879296dbe1f;p=openldap diff --git a/libraries/libldap/result.c b/libraries/libldap/result.c index 29c0b6f55e..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-2010 The OpenLDAP Foundation. + * Copyright 1998-2012 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -66,8 +66,8 @@ #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, @@ -120,6 +120,7 @@ ldap_result( return rc; } +/* protected by res_mutex */ static LDAPMessage * chkResponseList( LDAP *ld, @@ -144,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", @@ -164,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; } @@ -231,6 +230,7 @@ chkResponseList( return lm; } +/* protected by res_mutex */ static int wait4msg( LDAP *ld, @@ -284,9 +284,7 @@ wait4msg( if ( ldap_debug & LDAP_DEBUG_TRACE ) { Debug( LDAP_DEBUG_TRACE, "wait4msg continue ld %p msgid %d all %d\n", (void *)ld, msgid, all ); - LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); ldap_dump_connection( ld, ld->ld_conns, 1 ); - LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); LDAP_MUTEX_LOCK( &ld->ld_req_mutex ); ldap_dump_requests_and_responses( ld ); LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); @@ -308,7 +306,6 @@ wait4msg( break; } } - LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); if ( !lc_ready ) { int err; @@ -328,6 +325,7 @@ wait4msg( { ld->ld_errno = (rc == -1 ? LDAP_SERVER_DOWN : LDAP_TIMEOUT); + LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); return( rc ); } @@ -340,6 +338,7 @@ wait4msg( } 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 && @@ -347,10 +346,9 @@ wait4msg( ldap_is_write_ready( ld, ld->ld_requests->lr_conn->lconn_sb ) ) { + serviced = 1; ldap_int_flush_request( ld, ld->ld_requests ); } - LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); - LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); for ( lc = ld->ld_conns; rc == LDAP_MSG_X_KEEP_LOOKING && lc != NULL; lc = lnext ) @@ -358,27 +356,28 @@ wait4msg( if ( lc->lconn_status == LDAP_CONNST_CONNECTED && ldap_is_read_ready( ld, lc->lconn_sb ) ) { + serviced = 1; /* Don't let it get freed out from under us */ ++lc->lconn_refcnt; - LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); 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_MUTEX_LOCK( &ld->ld_req_mutex ); ldap_free_connection( ld, lc, 0, 1 ); - LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); } else { --lc->lconn_refcnt; } - LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); } else { lnext = lc->lconn_next; } } - LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); + 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 ) { @@ -432,6 +431,7 @@ wait4msg( } +/* protected by res_mutex, conn_mutex and req_mutex */ static ber_tag_t try_read1msg( LDAP *ld, @@ -443,7 +443,6 @@ try_read1msg( BerElement *ber; LDAPMessage *newmsg, *l, *prev; ber_int_t id; - int idx; ber_tag_t tag; ber_len_t len; int foundit = 0; @@ -461,6 +460,8 @@ try_read1msg( assert( lc != NULL ); 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 ); @@ -503,12 +504,8 @@ nextresp3: Debug( LDAP_DEBUG_CONNS, "ber_get_next failed.\n", 0, 0, 0 ); #endif -#ifdef EWOULDBLOCK if ( err == EWOULDBLOCK ) return LDAP_MSG_X_KEEP_LOOKING; -#endif -#ifdef EAGAIN if ( err == EAGAIN ) return LDAP_MSG_X_KEEP_LOOKING; -#endif ld->ld_errno = LDAP_SERVER_DOWN; --lc->lconn_refcnt; lc->lconn_status = 0; @@ -535,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 ) { @@ -548,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; } @@ -830,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 ); @@ -838,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; @@ -882,7 +886,7 @@ nextresp2: } /* - * RF 4511 unsolicited (id == 0) responses + * RFC 4511 unsolicited (id == 0) responses * shouldn't necessarily end the connection */ if ( lc != NULL && id != 0 ) { @@ -1337,35 +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 ) { - LDAP_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex ); - - assert( idxp != NULL ); + int ret, idx; assert( msgid >= 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 ) { - LDAP_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex ); - - /* NOTE: those assertions are repeated in ldap_int_bisect_delete() */ - assert( idx >= 0 ); - assert( (unsigned) 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; }