]> git.sur5r.net Git - openldap/commitdiff
allow per-target retry in searches; taint invalid connections; don't massage the...
authorPierangelo Masarati <ando@openldap.org>
Sat, 5 Nov 2005 14:44:43 +0000 (14:44 +0000)
committerPierangelo Masarati <ando@openldap.org>
Sat, 5 Nov 2005 14:44:43 +0000 (14:44 +0000)
servers/slapd/back-meta/back-meta.h
servers/slapd/back-meta/bind.c
servers/slapd/back-meta/conn.c
servers/slapd/back-meta/search.c

index 5d1911d3ed0d5eb6e44dff746e5bd6ff824822e2..a37f60196f0b713ba4541fac93ed9692d6c0fc5f 100644 (file)
@@ -184,6 +184,7 @@ typedef struct metaconn_t {
        struct slap_conn        *mc_conn;
        ldap_pvt_thread_mutex_t mc_mutex;
        unsigned                mc_refcnt;
+       int                     mc_tainted;
        
        struct berval           mc_local_ndn;
        /* NOTE: msc_mscflags is used to recycle the #define
index 3d59cf27d4965760eddca6d21e392c2f64fc3d4a..3d6867433629ca8c98c80199a9241cd0fac56f29 100644 (file)
@@ -46,7 +46,8 @@ meta_back_single_bind(
        Operation               *op,
        SlapReply               *rs,
        metaconn_t              *mc,
-       int                     candidate );
+       int                     candidate,
+       int                     massage );
 
 int
 meta_back_bind( Operation *op, SlapReply *rs )
@@ -124,6 +125,7 @@ meta_back_bind( Operation *op, SlapReply *rs )
        for ( i = 0; i < mi->mi_ntargets; i++ ) {
                int             lerr;
                Operation       op2 = *op;
+               int             massage = 1;
 
                /*
                 * Skip non-candidates
@@ -177,9 +179,12 @@ meta_back_bind( Operation *op, SlapReply *rs )
                        op2.o_req_ndn = mi->mi_targets[ i ].mt_pseudorootdn;
                        op2.orb_cred = mi->mi_targets[ i ].mt_pseudorootpw;
                        op2.orb_method = LDAP_AUTH_SIMPLE;
+
+                       massage = 0;
                }
                
-               lerr = meta_back_single_bind( &op2, rs, mc, i );
+               lerr = meta_back_single_bind( &op2, rs, mc, i, massage );
+
                if ( lerr != LDAP_SUCCESS ) {
                        rs->sr_err = lerr;
                        candidates[ i ].sr_tag = META_NOT_CANDIDATE;
@@ -274,12 +279,12 @@ meta_back_single_bind(
        Operation               *op,
        SlapReply               *rs,
        metaconn_t              *mc,
-       int                     candidate )
+       int                     candidate,
+       int                     massage )
 {
        metainfo_t              *mi = ( metainfo_t * )op->o_bd->be_private;
        metatarget_t            *mt = &mi->mi_targets[ candidate ];
        struct berval           mdn = BER_BVNULL;
-       dncookie                dc;
        metasingleconn_t        *msc = &mc->mc_conns[ candidate ];
        int                     msgid,
                                rebinding = 0;
@@ -300,14 +305,21 @@ meta_back_single_bind(
        /*
         * Rewrite the bind dn if needed
         */
-       dc.target = mt;
-       dc.conn = op->o_conn;
-       dc.rs = rs;
-       dc.ctx = "bindDN";
+       if ( massage ) {
+               dncookie                dc;
 
-       if ( ldap_back_dn_massage( &dc, &op->o_req_dn, &mdn ) ) {
-               send_ldap_result( op, rs );
-               return -1;
+               dc.target = mt;
+               dc.conn = op->o_conn;
+               dc.rs = rs;
+               dc.ctx = "bindDN";
+
+               if ( ldap_back_dn_massage( &dc, &op->o_req_dn, &mdn ) ) {
+                       send_ldap_result( op, rs );
+                       return -1;
+               }
+
+       } else {
+               mdn = op->o_req_dn;
        }
 
        /* FIXME: this fixes the bind problem right now; we need
@@ -378,27 +390,7 @@ retry:;
 
                        rc = slap_map_api2result( rs );
                        if ( rs->sr_err == LDAP_UNAVAILABLE && nretries != META_RETRY_NEVER ) {
-                               ldap_pvt_thread_mutex_lock( &mi->mi_conn_mutex );
-                               if ( mc->mc_refcnt == 1 ) {
-                                       meta_clear_one_candidate( msc );
-                                       LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
-
-                                       ( void )rewrite_session_delete( mt->mt_rwmap.rwm_rw, op->o_conn );
-
-                                       /* mc here must be the regular mc,
-                                        * reset and ready for init */
-                                       rc = meta_back_init_one_conn( op, rs,
-                                               mt, mc, msc, LDAP_BACK_CONN_ISPRIV( mc ),
-                                               candidate == mc->mc_authz_target,
-                                               LDAP_BACK_DONTSEND );
-
-                               } else {
-                                       /* can't do anything about it */
-                                       rc = 0;
-                               }
-
-                               ldap_pvt_thread_mutex_unlock( &mi->mi_conn_mutex );
-
+                               rc = meta_back_retry( op, rs, mc, candidate, LDAP_BACK_DONTSEND );
                                if ( rc ) {
                                        if ( nretries > 0 ) {
                                                nretries--;
@@ -552,6 +544,9 @@ retry:;
 
                        rc = slap_map_api2result( rs );
                        if ( rc == LDAP_UNAVAILABLE && nretries != META_RETRY_NEVER ) {
+                               /* NOTE: we do not use meta_back_retry() here
+                                * to avoid circular loops; mc_mutex is set
+                                * by the caller */
                                if ( dolock ) {
                                        ldap_pvt_thread_mutex_lock( &mi->mi_conn_mutex );
                                }
@@ -569,7 +564,6 @@ retry:;
                                                LDAP_BACK_CONN_ISPRIV( mc ),
                                                candidate == mc->mc_authz_target,
                                                LDAP_BACK_DONTSEND );
-                               
 
                                } else {
                                        /* can't do anything about it */
@@ -685,7 +679,7 @@ meta_back_dobind(
 
                        rootdn = mi->mi_targets[ i ].mt_pseudorootdn.bv_val;
 
-                       rc = meta_back_single_bind( &op2, rs, mc, i );
+                       rc = meta_back_single_bind( &op2, rs, mc, i, 0 );
 
                } else {
                        rc = meta_back_single_dobind( op, rs, mc, i,
index 8c341899d7c416ef53aaa3d52e1784e6b5c8e817..d005df178cb4c64a4dee42b65e27516548545dec 100644 (file)
@@ -172,6 +172,7 @@ metaconn_alloc(
        mc->mc_authz_target = META_BOUND_NONE;
        ldap_pvt_thread_mutex_init( &mc->mc_mutex );
        mc->mc_refcnt = 1;
+       mc->mc_tainted = 0;
 
        return mc;
 }
@@ -447,6 +448,10 @@ retry_lock:;
                        goto retry_lock;
                }
 
+               Debug( LDAP_DEBUG_ANY, "%s meta_back_retry: retrying uri=\"%s\" DN=\"%s\"\n",
+                       op->o_log_prefix, mt->mt_uri,
+                       BER_BVISNULL( &msc->msc_bound_ndn ) ? "" : msc->msc_bound_ndn.bv_val );
+
                meta_clear_one_candidate( msc );
                LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
 
@@ -465,6 +470,10 @@ retry_lock:;
                ldap_pvt_thread_mutex_unlock( &mc->mc_mutex );
        }
 
+       if ( rc != LDAP_SUCCESS ) {
+               mc->mc_tainted = 1;
+       }
+
        ldap_pvt_thread_mutex_unlock( &mi->mi_conn_mutex );
 
        return rc == LDAP_SUCCESS ? 1 : 0;
@@ -720,6 +729,13 @@ meta_back_getconn(
        mc = (metaconn_t *)avl_find( mi->mi_conntree, 
                (caddr_t)&mc_curr, meta_back_conn_cmp );
        if ( mc ) {
+               if ( mc->mc_tainted ) {
+                       rs->sr_err = LDAP_UNAVAILABLE;
+                       rs->sr_text = "remote server unavailable";
+                       ldap_pvt_thread_mutex_unlock( &mi->mi_conn_mutex );
+                       return NULL;
+               }
+                       
                mc->mc_refcnt++;
        }
        ldap_pvt_thread_mutex_unlock( &mi->mi_conn_mutex );
@@ -1122,5 +1138,8 @@ meta_back_release_conn(
        ldap_pvt_thread_mutex_lock( &mi->mi_conn_mutex );
        assert( mc->mc_refcnt > 0 );
        mc->mc_refcnt--;
+       if ( mc->mc_refcnt == 0 && mc->mc_tainted ) {
+               meta_back_conn_free( mc );
+       }
        ldap_pvt_thread_mutex_unlock( &mi->mi_conn_mutex );
 }
index d621b433076707ba3a2897f78aec220746acc09f..e3471692733d21077cf2140ada517d4093e28c03 100644 (file)
@@ -43,7 +43,13 @@ meta_send_entry(
        int             i,
        LDAPMessage     *e );
 
-static int
+typedef enum meta_search_candidate_t {
+       META_SEARCH_ERR = -1,
+       META_SEARCH_NOT_CANDIDATE,
+       META_SEARCH_CANDIDATE
+} meta_search_candidate_t;
+
+static meta_search_candidate_t
 meta_back_search_start(
        Operation               *op,
        SlapReply               *rs,
@@ -61,6 +67,7 @@ meta_back_search_start(
        struct berval   mfilter = BER_BVNULL;
        char            **mapped_attrs = NULL;
        int             rc;
+       meta_search_candidate_t retcode;
        struct timeval  tv, *tvp = NULL;
 
        /* should we check return values? */
@@ -105,7 +112,7 @@ meta_back_search_start(
                                /*
                                 * this target is no longer candidate
                                 */
-                               return 0;
+                               return META_SEARCH_NOT_CANDIDATE;
                        }
                        break;
 
@@ -145,7 +152,7 @@ meta_back_search_start(
                        /*
                         * this target is no longer candidate
                         */
-                       return 0;
+                       return META_SEARCH_NOT_CANDIDATE;
                }
        }
 
@@ -161,14 +168,14 @@ meta_back_search_start(
                rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
                rs->sr_text = "Operation not allowed";
                send_ldap_result( op, rs );
-               return -1;
+               return META_SEARCH_ERR;
 
        case REWRITE_REGEXEC_ERR:
 
                /*
                 * this target is no longer candidate
                 */
-               return 0;
+               return META_SEARCH_NOT_CANDIDATE;
        }
 
        /*
@@ -185,7 +192,7 @@ meta_back_search_start(
                /*
                 * this target is no longer candidate
                 */
-               rc = 0;
+               retcode = META_SEARCH_NOT_CANDIDATE;
                goto done;
        }
 
@@ -198,7 +205,7 @@ meta_back_search_start(
                /*
                 * this target is no longer candidate
                 */
-               rc = 0;
+               retcode = META_SEARCH_NOT_CANDIDATE;
                goto done;
        }
 
@@ -211,11 +218,11 @@ meta_back_search_start(
                        op->o_ctrls, NULL, tvp, op->ors_slimit,
                        &candidates[ candidate ].sr_msgid ); 
        if ( rc == LDAP_SUCCESS ) {
-               rc = 1;
+               retcode = META_SEARCH_CANDIDATE;
 
        } else {
                candidates[ candidate ].sr_msgid = -1;
-               rc = 0;
+               retcode = META_SEARCH_NOT_CANDIDATE;
        }
 
 done:;
@@ -229,7 +236,7 @@ done:;
                free( mbase.bv_val );
        }
 
-       return rc;
+       return retcode;
 }
 
 int
@@ -284,14 +291,15 @@ meta_back_search( Operation *op, SlapReply *rs )
 
                switch ( meta_back_search_start( op, rs, &dc, msc, i, candidates ) )
                {
-               case 0:
+               case META_SEARCH_NOT_CANDIDATE:
                        break;
 
-               case 1:
+               case META_SEARCH_CANDIDATE:
+                       candidates[ i ].sr_type = REP_INTERMEDIATE;
                        ++ncandidates;
                        break;
 
-               case -1:
+               case META_SEARCH_ERR:
                        rc = -1;
                        goto finish;
                }
@@ -386,6 +394,7 @@ meta_back_search( Operation *op, SlapReply *rs )
                         * get a LDAP_TIMELIMIT_EXCEEDED from
                         * one of them ...
                         */
+get_result:;
                        rc = ldap_result( msc->msc_ld, candidates[ i ].sr_msgid,
                                        0, &tv, &res );
 
@@ -411,21 +420,37 @@ meta_back_search( Operation *op, SlapReply *rs )
                        } else if ( rc == -1 ) {
 really_bad:;
                                /* something REALLY bad happened! */
-                               ( void )meta_clear_unused_candidates( op, -1 );
-                               rs->sr_err = LDAP_OTHER;
-                               savepriv = op->o_private;
-                               op->o_private = (void *)i;
-                               send_ldap_result( op, rs );
-                               op->o_private = savepriv;
-                               
-                               /* anything else needs be done? */
-
-                               /* FIXME: res should not need to be freed */
-                               assert( res == NULL );
+                               if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
+                                       candidates[ i ].sr_type = REP_RESULT;
+
+                                       if ( meta_back_retry( op, rs, mc, i, LDAP_BACK_DONTSEND ) ) {
+                                               switch ( meta_back_search_start( op, rs, &dc, msc, i, candidates ) )
+                                               {
+                                               case META_SEARCH_CANDIDATE:
+                                                       goto get_result;
+
+                                               default:
+                                                       rc = rs->sr_err = LDAP_OTHER;
+                                                       goto finish;
+                                               }
+                                       }
+                               }
 
-                               goto finish;
+                               /*
+                                * When no candidates are left,
+                                * the outer cycle finishes
+                                */
+                               candidates[ i ].sr_msgid = -1;
+                               --ncandidates;
+                               rs->sr_err = candidates[ i ].sr_err = LDAP_OTHER;
+                               rs->sr_text = "remote server unavailable";
 
                        } else if ( rc == LDAP_RES_SEARCH_ENTRY ) {
+                               if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
+                                       /* don't retry any more... */
+                                       candidates[ i ].sr_type = REP_RESULT;
+                               }
+
                                if ( --op->ors_slimit == -1 ) {
                                        ldap_msgfree( res );
                                        res = NULL;
@@ -477,6 +502,11 @@ really_bad:;
                                char            **references = NULL;
                                int             cnt;
 
+                               if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
+                                       /* don't retry any more... */
+                                       candidates[ i ].sr_type = REP_RESULT;
+                               }
+
                                is_ok++;
 
                                rc = ldap_parse_reference( msc->msc_ld, res,
@@ -525,7 +555,7 @@ really_bad:;
 
                                /* cleanup */
                                if ( references ) {
-                                       ldap_value_free( references );
+                                       ber_memvfree( (void **)references );
                                }
 
                                if ( rs->sr_ctrls ) {
@@ -537,6 +567,11 @@ really_bad:;
                                char            buf[ SLAP_TEXT_BUFLEN ];
                                char            **references = NULL;
 
+                               if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
+                                       /* don't retry any more... */
+                                       candidates[ i ].sr_type = REP_RESULT;
+                               }
+
                                if ( ldap_parse_result( msc->msc_ld,
                                                        res,
                                                        &candidates[ i ].sr_err,
@@ -550,6 +585,7 @@ really_bad:;
                                                        LDAP_OPT_ERROR_NUMBER,
                                                        &rs->sr_err );
                                        sres = slap_map_api2result( rs );
+                                       candidates[ i ].sr_type = REP_RESULT;
                                        goto really_bad;
                                }
 
@@ -611,7 +647,7 @@ really_bad:;
                                        ( void )ldap_back_referral_result_rewrite( &dc, sr_ref );
                                
                                        /* cleanup */
-                                       ldap_value_free( references );
+                                       ber_memvfree( (void **)references );
 
                                        if ( rs->sr_v2ref == NULL ) {
                                                rs->sr_v2ref = sr_ref;