--- libraries/libldap/result.c 2006/03/24 00:18:36 1.124 +++ libraries/libldap/result.c 2006/08/20 17:04:46 1.124.2.4 @@ -1,5 +1,5 @@ /* result.c - wait for an ldap result */ -/* $OpenLDAP: pkg/ldap/libraries/libldap/result.c,v 1.123 2006/02/14 22:18:12 kurt Exp $ */ +/* $OpenLDAP: pkg/ldap/libraries/libldap/result.c,v 1.124.2.3 2006/08/17 23:50:26 kurt Exp $ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2006 The OpenLDAP Foundation. @@ -37,17 +37,17 @@ * can be found in the file "build/LICENSE-2.0.1" in this distribution * of OpenLDAP Software. */ -/* Portions Copyright (C) The Internet Society (1997) - * ASN.1 fragments are from RFC 2251; see RFC for full legal notices. +/* Portions Copyright (C) The Internet Society (2006) + * ASN.1 fragments are from RFC 4511; see RFC for full legal notices. */ /* - * LDAPv3 (RFC2251) + * LDAPv3 (RFC 4511) * LDAPResult ::= SEQUENCE { - * resultCode ENUMERATED { ... }, - * matchedDN LDAPDN, - * errorMessage LDAPString, - * referral Referral OPTIONAL + * resultCode ENUMERATED { ... }, + * matchedDN LDAPDN, + * diagnosticMessage LDAPString, + * referral [3] Referral OPTIONAL * } * Referral ::= SEQUENCE OF LDAPURL (one or more) * LDAPURL ::= LDAPString (limited to URL chars) @@ -140,16 +140,22 @@ chkResponseList( int all) { LDAPMessage *lm, **lastlm, *nextlm; - /* + + /* * Look through the list of responses we have received on * this association and see if the response we're interested in * is there. If it is, return it. If not, call wait4msg() to * wait until it arrives or timeout occurs. */ +#ifdef LDAP_R_COMPILE + LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex ); +#endif + Debug( LDAP_DEBUG_TRACE, "ldap_chkResponseList ld %p msgid %d all %d\n", (void *)ld, msgid, all ); + lastlm = &ld->ld_responses; for ( lm = ld->ld_responses; lm != NULL; lm = nextlm ) { nextlm = lm->lm_next; @@ -233,11 +239,15 @@ wait4msg( *tvp; time_t start_time = 0; time_t tmp_time; - LDAPConn *lc, *nextlc; + LDAPConn *lc; assert( ld != NULL ); assert( result != NULL ); +#ifdef LDAP_R_COMPILE + LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex ); +#endif + #ifdef LDAP_DEBUG if ( timeout == NULL ) { Debug( LDAP_DEBUG_TRACE, "wait4msg ld %p msgid %d (infinite timeout)\n", @@ -263,12 +273,22 @@ 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_dump_requests_and_responses( ld ); +#ifdef LDAP_R_COMPILE + ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex ); +#endif } #endif /* LDAP_DEBUG */ - if ( (*result = chkResponseList(ld, msgid, all)) != NULL ) { + if ( ( *result = chkResponseList( ld, msgid, all ) ) != NULL ) { rc = (*result)->lm_msgtype; } else { @@ -277,10 +297,10 @@ wait4msg( #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex ); #endif - for ( lc = ld->ld_conns; lc != NULL; lc = nextlc ) { - nextlc = lc->lconn_next; + for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) { if ( ber_sockbuf_ctrl( lc->lconn_sb, - LBER_SB_OPT_DATA_READY, NULL ) ) { + LBER_SB_OPT_DATA_READY, NULL ) ) + { #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex ); #endif @@ -308,7 +328,7 @@ wait4msg( if ( rc == 0 || ( rc == -1 && ( !LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_RESTART) - || errno != EINTR ))) + || errno != EINTR ) ) ) { ld->ld_errno = (rc == -1 ? LDAP_SERVER_DOWN : LDAP_TIMEOUT); @@ -333,22 +353,34 @@ wait4msg( 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 = nextlc ) + for ( lc = ld->ld_conns; + rc == LDAP_MSG_X_KEEP_LOOKING && lc != NULL; ) { - nextlc = lc->lconn_next; if ( lc->lconn_status == LDAP_CONNST_CONNECTED && - ldap_is_read_ready( ld, lc->lconn_sb )) + 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 ); - if ( lc == NULL ) lc = nextlc; #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; + } } + + /* next conn */ + lc = lc->lconn_next; } #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex ); @@ -416,6 +448,10 @@ try_read1msg( assert( lcp != NULL ); assert( *lcp != NULL ); +#ifdef LDAP_R_COMPILE + LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex ); +#endif + Debug( LDAP_DEBUG_TRACE, "read1msg: ld %p msgid %d all %d\n", (void *)ld, msgid, all ); @@ -423,7 +459,7 @@ try_read1msg( retry: if ( lc->lconn_ber == NULL ) { - lc->lconn_ber = ldap_alloc_ber_with_options(ld); + lc->lconn_ber = ldap_alloc_ber_with_options( ld ); if( lc->lconn_ber == NULL ) { return -1; @@ -439,33 +475,35 @@ retry: if ( LDAP_IS_UDP(ld) ) { struct sockaddr from; ber_int_sb_read( lc->lconn_sb, &from, sizeof(struct sockaddr) ); - if (ld->ld_options.ldo_version == LDAP_VERSION2) isv2=1; + if (ld->ld_options.ldo_version == LDAP_VERSION2) isv2 = 1; } nextresp3: #endif tag = ber_get_next( lc->lconn_sb, &len, ber ); - if ( tag == LDAP_TAG_MESSAGE ) { + switch ( tag ) { + case LDAP_TAG_MESSAGE: /* * We read a complete message. * The connection should no longer need this ber. */ lc->lconn_ber = NULL; - } - if ( tag != LDAP_TAG_MESSAGE ) { - if ( tag == LBER_DEFAULT) { + break; + + case LBER_DEFAULT: #ifdef LDAP_DEBUG - Debug( LDAP_DEBUG_CONNS, - "ber_get_next failed.\n", 0, 0, 0 ); + Debug( LDAP_DEBUG_CONNS, + "ber_get_next failed.\n", 0, 0, 0 ); #endif #ifdef EWOULDBLOCK - if (errno==EWOULDBLOCK) return LDAP_MSG_X_KEEP_LOOKING; + if ( errno == EWOULDBLOCK ) return LDAP_MSG_X_KEEP_LOOKING; #endif #ifdef EAGAIN - if (errno == EAGAIN) return LDAP_MSG_X_KEEP_LOOKING; + if ( errno == EAGAIN ) return LDAP_MSG_X_KEEP_LOOKING; #endif - ld->ld_errno = LDAP_SERVER_DOWN; - return -1; - } + ld->ld_errno = LDAP_SERVER_DOWN; + return -1; + + default: ld->ld_errno = LDAP_LOCAL_ERROR; return -1; } @@ -493,7 +531,7 @@ retry_ber: if ( lr == NULL ) { Debug( LDAP_DEBUG_ANY, "no request for response on ld %p msgid %ld (tossing)\n", - (void *)ld, (long) id, 0 ); + (void *)ld, (long)id, 0 ); goto retry_ber; } #ifdef LDAP_CONNECTIONLESS @@ -546,7 +584,7 @@ nextresp2: if ( refer_cnt > 0 ) { /* sucessfully chased reference */ /* If haven't got end search, set chasing referrals */ - if( lr->lr_status != LDAP_REQST_COMPLETED) { + if ( lr->lr_status != LDAP_REQST_COMPLETED ) { lr->lr_status = LDAP_REQST_CHASINGREFS; Debug( LDAP_DEBUG_TRACE, "read1msg: search ref chased, " @@ -604,7 +642,7 @@ nextresp2: * Note: refs arrary is freed by ldap_chase_v3referrals */ refer_cnt = ldap_chase_v3referrals( ld, lr, refs, - 0, &lr->lr_res_error, &hadref ); + 0, &lr->lr_res_error, &hadref ); lr->lr_status = LDAP_REQST_COMPLETED; Debug( LDAP_DEBUG_TRACE, "read1msg: referral chased, mark request completed, ld %p msgid %d\n", @@ -657,13 +695,11 @@ 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 ); - } else { - lr->lr_res_error = 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; } lr_res_error = NULL; } @@ -754,12 +790,12 @@ nextresp2: /* Check if all requests are finished, lr is now parent */ tmplr = lr; - if (tmplr->lr_status == LDAP_REQST_COMPLETED) { + if ( tmplr->lr_status == LDAP_REQST_COMPLETED ) { for ( tmplr=lr->lr_child; tmplr != NULL; tmplr=tmplr->lr_refnext) { - if( tmplr->lr_status != LDAP_REQST_COMPLETED) break; + if ( tmplr->lr_status != LDAP_REQST_COMPLETED ) break; } } @@ -779,7 +815,8 @@ lr->lr_res_matched ? lr->lr_res_matched ber_free( ber, 1 ); ber = NULL; if ( build_result_ber( ld, &ber, lr ) - == LBER_ERROR ) { + == LBER_ERROR ) + { rc = -1; /* fatal error */ } } @@ -1159,13 +1196,21 @@ ldap_msgdelete( LDAP *ld, int msgid ) /* + * ldap_abandoned + * * return 1 if message msgid is waiting to be abandoned, 0 otherwise + * + * expects ld_res_mutex to be locked */ static int ldap_abandoned( LDAP *ld, ber_int_t msgid ) { int i; +#ifdef LDAP_R_COMPILE + LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex ); +#endif + if ( ld->ld_abandoned == NULL ) return( 0 ); @@ -1177,11 +1222,20 @@ ldap_abandoned( LDAP *ld, ber_int_t msgi } +/* + * ldap_mark_abandoned + * + * expects ld_res_mutex to be locked + */ static int ldap_mark_abandoned( LDAP *ld, ber_int_t msgid ) { int i; +#ifdef LDAP_R_COMPILE + LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex ); +#endif + if ( ld->ld_abandoned == NULL ) return( -1 );