X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=libraries%2Flibldap%2Fresult.c;h=05580b793cfa8215566cb412215f35021927bf8b;hb=a5cad3f18a4b8fbbbb1bfc5db9d00022d9ebbfc4;hp=804f5d671c5471204810a7de40f3f1b8b95cde01;hpb=d4324d5813c7de90a05ef1d3fefbe18a37cab6f8;p=openldap diff --git a/libraries/libldap/result.c b/libraries/libldap/result.c index 804f5d671c..05580b793c 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-2007 The OpenLDAP Foundation. + * Copyright 1998-2010 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -71,7 +71,7 @@ static int ldap_mark_abandoned LDAP_P(( LDAP *ld, ber_int_t msgid, int idx )); 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 ); @@ -118,19 +117,7 @@ ldap_result( 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; - } + rc = wait4msg( ld, msgid, all, timeout, result ); #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_unlock( &ld->ld_res_mutex ); @@ -244,7 +231,7 @@ chkResponseList( "ldap_chkResponseList returns ld %p NULL\n", (void *)ld, 0, 0); } else { Debug( LDAP_DEBUG_TRACE, - "ldap_chkResponseList returns ld %p msgid %d, type 0x%02lu\n", + "ldap_chkResponseList returns ld %p msgid %d, type 0x%02lx\n", (void *)ld, lm->lm_msgid, (unsigned long)lm->lm_msgtype ); } #endif @@ -263,9 +250,8 @@ wait4msg( int rc; struct timeval tv = { 0 }, tv0 = { 0 }, - *tvp; - time_t start_time = 0; - time_t tmp_time; + start_time_tv = { 0 }, + *tvp = NULL; LDAPConn *lc; assert( ld != NULL ); @@ -275,6 +261,11 @@ wait4msg( LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex ); #endif + if ( timeout == NULL && ld->ld_options.ldo_tm_api.tv_sec >= 0 ) { + tv = ld->ld_options.ldo_tm_api; + timeout = &tv; + } + #ifdef LDAP_DEBUG if ( timeout == NULL ) { Debug( LDAP_DEBUG_TRACE, "wait4msg ld %p msgid %d (infinite timeout)\n", @@ -285,13 +276,16 @@ wait4msg( } #endif /* LDAP_DEBUG */ - if ( timeout == NULL ) { - tvp = NULL; - } else { + if ( timeout != NULL && timeout->tv_sec != -1 ) { tv0 = *timeout; tv = *timeout; tvp = &tv; - start_time = time( NULL ); +#ifdef HAVE_GETTIMEOFDAY + gettimeofday( &start_time_tv, NULL ); +#else /* ! HAVE_GETTIMEOFDAY */ + time( &start_time_tv.tv_sec ); + start_time_tv.tv_usec = 0; +#endif /* ! HAVE_GETTIMEOFDAY */ } rc = LDAP_MSG_X_KEEP_LOOKING; @@ -315,7 +309,7 @@ wait4msg( } #endif /* LDAP_DEBUG */ - if ( ( *result = chkResponseList( ld, msgid, all ) ) != NULL ) { + if ( ( *result = chkResponseList( ld, msgid, all ) ) != NULL ) { rc = (*result)->lm_msgtype; } else { @@ -328,13 +322,6 @@ wait4msg( 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; } @@ -343,19 +330,21 @@ wait4msg( ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex ); #endif - if ( !lc_ready ) { + 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); @@ -366,70 +355,110 @@ wait4msg( rc = LDAP_MSG_X_KEEP_LOOKING; /* select interrupted: loop */ } else { - rc = LDAP_MSG_X_KEEP_LOOKING; + lc_ready = 1; + } + } + if ( lc_ready ) { + LDAPConn *lnext; + rc = LDAP_MSG_X_KEEP_LOOKING; #ifdef LDAP_R_COMPILE - ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex ); + 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 ); - } + 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 ); + 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; ) + 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 ) ) - { + /* Don't let it get freed out from under us */ + ++lc->lconn_refcnt; +#ifdef LDAP_R_COMPILE + ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex ); +#endif + 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 ) { #ifdef LDAP_R_COMPILE - ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex ); + ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex ); #endif - rc = try_read1msg( ld, msgid, all, &lc, result ); + ldap_free_connection( ld, lc, 0, 1 ); #ifdef LDAP_R_COMPILE - ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex ); + ldap_pvt_thread_mutex_unlock( &ld->ld_req_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; - } + } else { + --lc->lconn_refcnt; } - - /* next conn */ - lc = lc->lconn_next; - } #ifdef LDAP_R_COMPILE - ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex ); + ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex ); #endif + } else { + lnext = lc->lconn_next; + } } +#ifdef LDAP_R_COMPILE + ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex ); +#endif } } if ( rc == LDAP_MSG_X_KEEP_LOOKING && tvp != NULL ) { - tmp_time = time( NULL ); - tv0.tv_sec -= ( tmp_time - start_time ); - if ( tv0.tv_sec <= 0 ) { - rc = 0; /* timed out */ + struct timeval curr_time_tv = { 0 }, + delta_time_tv = { 0 }; + +#ifdef HAVE_GETTIMEOFDAY + gettimeofday( &curr_time_tv, NULL ); +#else /* ! HAVE_GETTIMEOFDAY */ + time( &curr_time_tv.tv_sec ); + curr_time_tv.tv_usec = 0; +#endif /* ! HAVE_GETTIMEOFDAY */ + + /* delta_time = tmp_time - start_time */ + delta_time_tv.tv_sec = curr_time_tv.tv_sec - start_time_tv.tv_sec; + delta_time_tv.tv_usec = curr_time_tv.tv_usec - start_time_tv.tv_usec; + if ( delta_time_tv.tv_usec < 0 ) { + delta_time_tv.tv_sec--; + delta_time_tv.tv_usec += 1000000; + } + + /* tv0 < delta_time ? */ + if ( ( tv0.tv_sec < delta_time_tv.tv_sec ) || + ( ( tv0.tv_sec == delta_time_tv.tv_sec ) && ( tv0.tv_usec < delta_time_tv.tv_usec ) ) ) + { + rc = 0; /* timed out */ ld->ld_errno = LDAP_TIMEOUT; break; } + + /* tv0 -= delta_time */ + tv0.tv_sec -= delta_time_tv.tv_sec; + tv0.tv_usec -= delta_time_tv.tv_usec; + if ( tv0.tv_usec < 0 ) { + tv0.tv_sec--; + tv0.tv_usec += 1000000; + } + tv.tv_sec = tv0.tv_sec; + tv.tv_usec = tv0.tv_usec; + + Debug( LDAP_DEBUG_TRACE, "wait4msg ld %p %ld s %ld us to go\n", + (void *)ld, (long) tv.tv_sec, (long) tv.tv_usec ); - Debug( LDAP_DEBUG_TRACE, "wait4msg ld %p %ld secs to go\n", - (void *)ld, (long) tv.tv_sec, 0 ); - start_time = tmp_time; + start_time_tv.tv_sec = curr_time_tv.tv_sec; + start_time_tv.tv_usec = curr_time_tv.tv_usec; } } @@ -442,7 +471,7 @@ try_read1msg( LDAP *ld, ber_int_t msgid, int all, - LDAPConn **lcp, + LDAPConn *lc, LDAPMessage **result ) { BerElement *ber; @@ -453,9 +482,8 @@ try_read1msg( 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 @@ -464,8 +492,7 @@ 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 ); @@ -474,8 +501,6 @@ try_read1msg( 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 ); @@ -509,17 +534,20 @@ 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; + if ( err == EWOULDBLOCK ) return LDAP_MSG_X_KEEP_LOOKING; #endif #ifdef EAGAIN - if ( sock_errno() == EAGAIN ) return LDAP_MSG_X_KEEP_LOOKING; + if ( err == EAGAIN ) return LDAP_MSG_X_KEEP_LOOKING; #endif ld->ld_errno = LDAP_SERVER_DOWN; + --lc->lconn_refcnt; + lc->lconn_status = 0; return -1; default: @@ -536,6 +564,11 @@ nextresp3: /* id == 0 iff unsolicited notification message (RFC 4511) */ + /* id < 0 is invalid, just toss it. FIXME: should we disconnect? */ + if ( id < 0 ) { + goto retry_ber; + } + /* if it's been abandoned, toss it */ if ( id > 0 ) { if ( ldap_abandoned( ld, id, &idx ) ) { @@ -556,8 +589,8 @@ nextresp3: } Debug( LDAP_DEBUG_ANY, - "abandoned/discarded ld %p msgid %ld message type %s\n", - (void *)ld, (long)id, ldap_int_msgtype2str( tag ) ); + "abandoned/discarded ld %p msgid %d message type %s\n", + (void *)ld, id, ldap_int_msgtype2str( tag ) ); retry_ber: ber_free( ber, 1 ); @@ -583,8 +616,8 @@ retry_ber: } Debug( LDAP_DEBUG_ANY, - "no request for response on ld %p msgid %ld message type %s (tossing)\n", - (void *)ld, (long)id, msg ); + "no request for response on ld %p msgid %d message type %s (tossing)\n", + (void *)ld, id, msg ); goto retry_ber; } @@ -594,6 +627,7 @@ retry_ber: ber_scanf(ber, "x{"); } nextresp2: + ; #endif } @@ -606,8 +640,8 @@ nextresp2: } Debug( LDAP_DEBUG_TRACE, - "read1msg: ld %p msgid %ld message type %s\n", - (void *)ld, (long)lr->lr_msgid, ldap_int_msgtype2str( tag ) ); + "read1msg: ld %p msgid %d message type %s\n", + (void *)ld, id, ldap_int_msgtype2str( tag ) ); if ( id == 0 ) { /* unsolicited notification message (RFC 4511) */ @@ -713,8 +747,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; @@ -811,6 +846,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 ) { @@ -854,8 +893,8 @@ nextresp2: { id = lr->lr_msgid; tag = lr->lr_res_msgtype; - Debug( LDAP_DEBUG_ANY, "request done: ld %p msgid %ld\n", - (void *)ld, (long) id, 0 ); + Debug( LDAP_DEBUG_TRACE, "request done: ld %p msgid %d\n", + (void *)ld, id, 0 ); Debug( LDAP_DEBUG_TRACE, "res_errno: %d, res_error: <%s>, " "res_matched: <%s>\n", @@ -878,15 +917,13 @@ nextresp2: lr = NULL; } - 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; + /* + * RF 4511 unsolicited (id == 0) responses + * shouldn't necessarily end the connection + */ + if ( lc != NULL && id != 0 ) { + --lc->lconn_refcnt; + lc = NULL; } } } @@ -906,14 +943,14 @@ nextresp2: if ( id == 0 && msgid > LDAP_RES_UNSOLICITED ) { int is_nod = 0; - tag = ber_peek_tag( ber, &len ); + tag = ber_peek_tag( &tmpber, &len ); /* we have a res oid */ if ( tag == LDAP_TAG_EXOP_RES_OID ) { static struct berval bv_nod = BER_BVC( LDAP_NOTICE_OF_DISCONNECTION ); struct berval resoid = BER_BVNULL; - if ( ber_scanf( ber, "m", &resoid ) == LBER_ERROR ) { + if ( ber_scanf( &tmpber, "m", &resoid ) == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; ber_free( ber, 1 ); return -1; @@ -923,7 +960,7 @@ nextresp2: is_nod = ber_bvcmp( &resoid, &bv_nod ) == 0; - tag = ber_peek_tag( ber, &len ); + tag = ber_peek_tag( &tmpber, &len ); } #if 0 /* don't need right now */ @@ -931,7 +968,7 @@ nextresp2: if ( tag == LDAP_TAG_EXOP_RES_VALUE ) { struct berval resdata; - if ( ber_scanf( ber, "m", &resdata ) == LBER_ERROR ) { + if ( ber_scanf( &tmpber, "m", &resdata ) == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; ber_free( ber, 0 ); return ld->ld_errno; @@ -952,17 +989,13 @@ 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 - *lcp = NULL; + --lc->lconn_refcnt; } - return LDAP_RES_EXTENDED; + /* need to return -1, because otherwise + * a valid result is expected */ + ld->ld_errno = lderr; + return -1; } } @@ -1066,7 +1099,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; @@ -1104,8 +1138,8 @@ nextresp2: goto exit; } - Debug( LDAP_DEBUG_TRACE, "adding response ld %p msgid %ld type %ld:\n", - (void *)ld, (long) newmsg->lm_msgid, (long) newmsg->lm_msgtype ); + Debug( LDAP_DEBUG_TRACE, "adding response ld %p msgid %d type %ld:\n", + (void *)ld, newmsg->lm_msgid, (long) newmsg->lm_msgtype ); /* part of a search response - add to end of list of entries */ l->lm_chain_tail->lm_chain = newmsg; @@ -1355,7 +1389,6 @@ ldap_abandoned( LDAP *ld, ber_int_t msgid, int *idxp ) assert( idxp != NULL ); assert( msgid >= 0 ); - assert( ld->ld_nabandoned >= 0 ); return ldap_int_bisect_find( ld->ld_abandoned, ld->ld_nabandoned, msgid, idxp ); } @@ -1374,7 +1407,7 @@ ldap_mark_abandoned( LDAP *ld, ber_int_t msgid, int idx ) /* NOTE: those assertions are repeated in ldap_int_bisect_delete() */ assert( idx >= 0 ); - assert( idx < ld->ld_nabandoned ); + assert( (unsigned) idx < ld->ld_nabandoned ); assert( ld->ld_abandoned[ idx ] == msgid ); return ldap_int_bisect_delete( &ld->ld_abandoned, &ld->ld_nabandoned,