/* * meta_back_conn_free() * * actually frees a connection; the reference count must be 0, * and it must not (or no longer) be in the cache. */ void meta_back_conn_free( void *v_mc ) { metaconn_t *mc = v_mc; int ntargets; assert( mc != NULL ); assert( mc->mc_refcnt == 0 ); /* at least one must be present... */ ntargets = mc->mc_info->mi_ntargets; assert( ntargets > 0 ); for ( ; ntargets--; ) { (void)meta_clear_one_candidate( NULL, mc, ntargets ); } if ( !BER_BVISNULL( &mc->mc_local_ndn ) ) { free( mc->mc_local_ndn.bv_val ); } free( mc ); }
/* * meta_back_getconn * * Prepares the connection structure * * FIXME: This function needs to receive some info on the type of operation * it is invoked by, so that only the correct pool of candidate targets * is initialized in case no connection was available yet. * * At present a flag that says whether the candidate target must be unique * is passed; eventually an operation agent will be used. */ struct metaconn * meta_back_getconn( struct metainfo *li, Connection *conn, Operation *op, int op_type, struct berval *ndn, int *candidate ) { struct metaconn *lc, lc_curr; int cached = -1, i = -1, err = LDAP_SUCCESS; int new_conn = 0; /* Searches for a metaconn in the avl tree */ lc_curr.conn = conn; ldap_pvt_thread_mutex_lock( &li->conn_mutex ); lc = (struct metaconn *)avl_find( li->conntree, (caddr_t)&lc_curr, meta_back_conn_cmp ); ldap_pvt_thread_mutex_unlock( &li->conn_mutex ); /* Looks like we didn't get a bind. Open a new session... */ if ( !lc ) { lc = metaconn_alloc( li->ntargets ); lc->conn = conn; new_conn = 1; } /* * looks in cache, if any */ if ( li->cache.ttl != META_DNCACHE_DISABLED ) { cached = i = meta_dncache_get_target( &li->cache, ndn ); } if ( op_type == META_OP_REQUIRE_SINGLE ) { /* * tries to get a unique candidate * (takes care of default target */ if ( i < 0 ) { i = meta_back_select_unique_candidate( li, ndn ); } /* * if any is found, inits the connection */ if ( i < 0 ) { if ( new_conn ) { metaconn_free( lc ); } send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, NULL, "", NULL, NULL ); return NULL; } #ifdef NEW_LOGGING LDAP_LOG( BACK_META, INFO, "meta_back_getconn: got target %d for ndn=\"%s\" from cache\n", i, ndn->bv_val, 0 ); #else /* !NEW_LOGGING */ Debug( LDAP_DEBUG_CACHE, "==>meta_back_getconn: got target %d for ndn=\"%s\" from cache\n%s", i, ndn->bv_val, "" ); #endif /* !NEW_LOGGING */ /* * Clear all other candidates */ ( void )meta_clear_unused_candidates( li, lc, i, 0 ); /* * The target is activated; if needed, it is * also init'd. In case of error, init_one_conn * sends the appropriate result. */ err = init_one_conn( conn, op, li->targets[ i ], &lc->conns[ i ] ); if ( err != LDAP_SUCCESS ) { /* * FIXME: in case one target cannot * be init'd, should the other ones * be tried? */ ( void )meta_clear_one_candidate( &lc->conns[ i ], 1 ); if ( new_conn ) { metaconn_free( lc ); } return NULL; } if ( candidate ) { *candidate = i; } /* * require all connections ... */ } else if (op_type == META_OP_REQUIRE_ALL) { for ( i = 0; i < li->ntargets; i++ ) { /* * The target is activated; if needed, it is * also init'd */ int lerr = init_one_conn( conn, op, li->targets[ i ], &lc->conns[ i ] ); if ( lerr != LDAP_SUCCESS ) { /* * FIXME: in case one target cannot * be init'd, should the other ones * be tried? */ ( void )meta_clear_one_candidate( &lc->conns[ i ], 1 ); err = lerr; continue; } } /* * if no unique candidate ... */ } else { for ( i = 0; i < li->ntargets; i++ ) { if ( i == cached || meta_back_is_candidate( &li->targets[ i ]->suffix, ndn ) ) { /* * The target is activated; if needed, it is * also init'd */ int lerr = init_one_conn( conn, op, li->targets[ i ], &lc->conns[ i ] ); if ( lerr != LDAP_SUCCESS ) { /* * FIXME: in case one target cannot * be init'd, should the other ones * be tried? */ ( void )meta_clear_one_candidate( &lc->conns[ i ], 1 ); err = lerr; continue; } } } } if ( new_conn ) { /* * Inserts the newly created metaconn in the avl tree */ ldap_pvt_thread_mutex_lock( &li->conn_mutex ); err = avl_insert( &li->conntree, ( caddr_t )lc, meta_back_conn_cmp, meta_back_conn_dup ); #if PRINT_CONNTREE > 0 myprint( li->conntree ); #endif /* PRINT_CONNTREE */ ldap_pvt_thread_mutex_unlock( &li->conn_mutex ); #ifdef NEW_LOGGING LDAP_LOG( BACK_META, INFO, "meta_back_getconn: conn %ld inserted\n", lc->conn->c_connid, 0, 0); #else /* !NEW_LOGGING */ Debug( LDAP_DEBUG_TRACE, "=>meta_back_getconn: conn %ld inserted\n%s%s", lc->conn->c_connid, "", "" ); #endif /* !NEW_LOGGING */ /* * Err could be -1 in case a duplicate metaconn is inserted */ if ( err != 0 ) { send_ldap_result( conn, op, LDAP_OTHER, NULL, "Internal server error", NULL, NULL ); metaconn_free( lc ); return NULL; } } else { #ifdef NEW_LOGGING LDAP_LOG( BACK_META, INFO, "meta_back_getconn: conn %ld fetched\n", lc->conn->c_connid, 0, 0 ); #else /* !NEW_LOGGING */ Debug( LDAP_DEBUG_TRACE, "=>meta_back_getconn: conn %ld fetched\n%s%s", lc->conn->c_connid, "", "" ); #endif /* !NEW_LOGGING */ } return lc; }
static int meta_back_bind_op_result( Operation *op, SlapReply *rs, metaconn_t *mc, int candidate, int msgid, ldap_back_send_t sendok, int dolock ) { metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; metatarget_t *mt = mi->mi_targets[ candidate ]; metasingleconn_t *msc = &mc->mc_conns[ candidate ]; LDAPMessage *res; struct timeval tv; int rc; int nretries = mt->mt_nretries; char buf[ SLAP_TEXT_BUFLEN ]; Debug( LDAP_DEBUG_TRACE, ">>> %s meta_back_bind_op_result[%d]\n", op->o_log_prefix, candidate ); /* make sure this is clean */ assert( rs->sr_ctrls == NULL ); if ( rs->sr_err == LDAP_SUCCESS ) { time_t stoptime = (time_t)(-1), timeout; int timeout_err = op->o_protocol >= LDAP_VERSION3 ? LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER; const char *timeout_text = "Operation timed out"; slap_op_t opidx = slap_req2op( op->o_tag ); /* since timeout is not specified, compute and use * the one specific to the ongoing operation */ if ( opidx == (slap_op_t) LDAP_REQ_SEARCH ) { if ( op->ors_tlimit <= 0 ) { timeout = 0; } else { timeout = op->ors_tlimit; timeout_err = LDAP_TIMELIMIT_EXCEEDED; timeout_text = NULL; } } else { timeout = mt->mt_timeout[ opidx ]; } /* better than nothing :) */ if ( timeout == 0 ) { if ( mi->mi_idle_timeout ) { timeout = mi->mi_idle_timeout; } else if ( mi->mi_conn_ttl ) { timeout = mi->mi_conn_ttl; } } if ( timeout ) { stoptime = op->o_time + timeout; } LDAP_BACK_TV_SET( &tv ); /* * handle response!!! */ retry:; rc = ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res ); switch ( rc ) { case 0: if ( nretries != META_RETRY_NEVER || ( timeout && slap_get_time() <= stoptime ) ) { ldap_pvt_thread_yield(); if ( nretries > 0 ) { nretries--; } tv = mt->mt_bind_timeout; goto retry; } /* don't let anyone else use this handler, * because there's a pending bind that will not * be acknowledged */ if ( dolock) { ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); } assert( LDAP_BACK_CONN_BINDING( msc ) ); #ifdef DEBUG_205 Debug( LDAP_DEBUG_ANY, "### %s meta_back_bind_op_result ldap_unbind_ext[%d] ld=%p\n", op->o_log_prefix, candidate, (void *)msc->msc_ld ); #endif /* DEBUG_205 */ meta_clear_one_candidate( op, mc, candidate ); if ( dolock ) { ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); } rs->sr_err = timeout_err; rs->sr_text = timeout_text; break; case -1: ldap_get_option( msc->msc_ld, LDAP_OPT_ERROR_NUMBER, &rs->sr_err ); snprintf( buf, sizeof( buf ), "err=%d (%s) nretries=%d", rs->sr_err, ldap_err2string( rs->sr_err ), nretries ); Debug( LDAP_DEBUG_ANY, "### %s meta_back_bind_op_result[%d]: %s.\n", op->o_log_prefix, candidate, buf ); break; default: /* only touch when activity actually took place... */ if ( mi->mi_idle_timeout != 0 && msc->msc_time < op->o_time ) { msc->msc_time = op->o_time; } /* FIXME: matched? referrals? response controls? */ rc = ldap_parse_result( msc->msc_ld, res, &rs->sr_err, NULL, NULL, NULL, NULL, 1 ); if ( rc != LDAP_SUCCESS ) { rs->sr_err = rc; } rs->sr_err = slap_map_api2result( rs ); break; } } rs->sr_err = slap_map_api2result( rs ); Debug( LDAP_DEBUG_TRACE, "<<< %s meta_back_bind_op_result[%d] err=%d\n", op->o_log_prefix, candidate, rs->sr_err ); return rs->sr_err; }