Example #1
0
static void
tx_sde(isc_task_t *task, isc_event_t *event) {
	isc_result_t	isc_result;

	UNUSED(task);
	UNUSED(event);

	/*
	 * Signal shutdown processing complete.
	 */
	isc_result = isc_mutex_lock(&Tx_mx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_mutex_lock failed %s\n",
		       isc_result_totext(isc_result));
		++Tx_nprobs;
	}

	isc_result = isc_condition_signal(&Tx_cv);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_condition_signal failed %s\n",
		       isc_result_totext(isc_result));
		++Tx_nprobs;
	}

	isc_result = isc_mutex_unlock(&Tx_mx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_mutex_unlock failed %s\n",
		       isc_result_totext(isc_result));
		++Tx_nprobs;
	}

	isc_event_free(&event);
}
Example #2
0
static void
t5_start_event(isc_task_t *task, isc_event_t *event) {
	isc_result_t	isc_result;

	UNUSED(task);

	t_info("t5_start_event\n");

	isc_result = isc_mutex_lock(&T5_mx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_mutex_lock failed %s\n",
		       isc_result_totext(isc_result));
		++T5_nprobs;
	}

	while (! T5_startflag) {
		(void) isc_condition_wait(&T5_cv, &T5_mx);
	}

	isc_result = isc_mutex_unlock(&T5_mx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_mutex_unlock failed %s\n",
		       isc_result_totext(isc_result));
		++T5_nprobs;
	}
	isc_event_free(&event);
}
static isc_result_t
odbc_findzone(void *driverarg, void *dbdata, const char *name)
{

	isc_result_t result;
	dbinstance_t *dbi = NULL;

	UNUSED(driverarg);

	/* run the query and get the result set from the database. */
	/* if result != ISC_R_SUCCESS cursor and mutex already cleaned up. */
	/* so we don't have to do it here. */
	result = odbc_get_resultset(name, NULL, NULL, FINDZONE, dbdata, &dbi);

	/* Check that we got a result set with data */
	if (result == ISC_R_SUCCESS &&
	    !sqlOK(SQLFetch(((odbc_db_t *) (dbi->dbconn))->stmnt))) {
		result = ISC_R_NOTFOUND;
	}

	if (dbi != NULL) {
		/* get rid of result set, we are done with it. */
		SQLCloseCursor(((odbc_db_t *) (dbi->dbconn))->stmnt);

#ifdef ISC_PLATFORM_USETHREADS

		/* free lock on dbi so someone else can use it. */
		isc_mutex_unlock(&dbi->instance_lock);
#endif
	}

	return result;
}
/*% Determine if the client is allowed to perform a zone transfer */
static isc_result_t
odbc_allowzonexfr(void *driverarg, void *dbdata, const char *name,
		  const char *client)
{
	isc_result_t result;
	dbinstance_t *dbi = NULL;

	UNUSED(driverarg);

	/* first check if the zone is supported by the database. */
	result = odbc_findzone(driverarg, dbdata, name);
	if (result != ISC_R_SUCCESS)
		return (ISC_R_NOTFOUND);

	/*
	 * if we get to this point we know the zone is supported by
	 * the database.  the only questions now are is the zone
	 * transfer is allowed for this client and did the config file
	 * have an allow zone xfr query
	 *
	 * Run our query, and get a result set from the database.  if
	 * result != ISC_R_SUCCESS cursor and mutex already cleaned
	 * up, so we don't have to do it here.
	 */
	result = odbc_get_resultset(name, NULL, client, ALLOWXFR,
				    dbdata, &dbi);

	/* if we get "not implemented", send it along. */
	if (result == ISC_R_NOTIMPLEMENTED)
		return result;

	/* Check that we got a result set with data */
	if (result == ISC_R_SUCCESS &&
	    !sqlOK(SQLFetch(((odbc_db_t *) (dbi->dbconn))->stmnt))) {
		result = ISC_R_NOPERM;
	}

	if (dbi != NULL) {
		/* get rid of result set, we are done with it. */
		SQLCloseCursor(((odbc_db_t *) (dbi->dbconn))->stmnt);

#ifdef ISC_PLATFORM_USETHREADS

		/* free lock on dbi so someone else can use it. */
		isc_mutex_unlock(&dbi->instance_lock);
#endif

	}

	return result;
}
Example #5
0
static void
t5_once_event(isc_task_t *task, isc_event_t *event) {

	isc_result_t	isc_result;

	t_info("t5_once_event\n");

	/*
	 * Allow task1 to start processing events.
	 */
	isc_result = isc_mutex_lock(&T5_mx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_mutex_lock failed %s\n",
		       isc_result_totext(isc_result));
		++T5_nprobs;
	}

	T5_startflag = 1;

	isc_result = isc_condition_broadcast(&T5_cv);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_condition_broadcast failed %s\n",
		       isc_result_totext(isc_result));
		++T5_nprobs;
	}

	isc_result = isc_mutex_unlock(&T5_mx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_mutex_unlock failed %s\n",
		       isc_result_totext(isc_result));
		++T5_nprobs;
	}

	isc_event_free(&event);
	isc_task_shutdown(task);
}
static inline void
CUNLOCK(void) {
	RUNTIME_CHECK(isc_mutex_unlock(&client_lock) == ISC_R_SUCCESS);
}
Example #7
0
/*%
 * This function is the real core of the driver.   Zone, record
 * and client strings are passed in (or NULL is passed if the
 * string is not available).  The type of query we want to run
 * is indicated by the query flag, and the dbdata object is passed
 * passed in to.  dbdata really holds either:
 *		1) a list of database instances (in multithreaded mode) OR
 *		2) a single database instance (in single threaded mode)
 * The function will construct the query and obtain an available
 * database instance (DBI).  It will then run the query and hopefully
 * obtain a result set.  Postgres is nice, in that once the result
 * set is returned, we can make the db connection available for another
 * thread to use, while this thread continues on.  So, the DBI is made
 * available ASAP by unlocking the instance_lock after we have cleaned
 * it up properly.
 */
static isc_result_t
postgres_get_resultset(const char *zone, const char *record,
		       const char *client, unsigned int query,
		       void *dbdata, PGresult **rs)
{
	isc_result_t result;
	dbinstance_t *dbi = NULL;
	char *querystring = NULL;
	unsigned int i = 0;
	unsigned int j = 0;

	/* temporarily get a unique thread # */
	unsigned int dlz_thread_num = 1+(int) (1000.0*rand()/(RAND_MAX+1.0));

	REQUIRE(*rs == NULL);

#if 0
	/* temporary logging message */
	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
		      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
		      "%d Getting DBI", dlz_thread_num);
#endif

	/* get db instance / connection */
#ifdef ISC_PLATFORM_USETHREADS

	/* find an available DBI from the list */
	dbi = postgres_find_avail_conn((db_list_t *) dbdata);

#else /* ISC_PLATFORM_USETHREADS */

	/*
	 * only 1 DBI - no need to lock instance lock either
	 * only 1 thread in the whole process, no possible contention.
	 */
	dbi =  (dbinstance_t *) dbdata;

#endif /* ISC_PLATFORM_USETHREADS */

#if 0
	/* temporary logging message */
	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
		      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
		      "%d Got DBI - checking query", dlz_thread_num);
#endif

	/* if DBI is null, can't do anything else */
	if (dbi == NULL) {
		result = ISC_R_FAILURE;
		goto cleanup;
	}

	/* what type of query are we going to run? */
	switch(query) {
	case ALLNODES:
		/*
		 * if the query was not passed in from the config file
		 * then we can't run it.  return not_implemented, so
		 * it's like the code for that operation was never
		 * built into the driver.... AHHH flexibility!!!
		 */
		if (dbi->allnodes_q == NULL) {
			result = ISC_R_NOTIMPLEMENTED;
			goto cleanup;
		}
		break;
	case ALLOWXFR:
		/* same as comments as ALLNODES */
		if (dbi->allowxfr_q == NULL) {
			result = ISC_R_NOTIMPLEMENTED;
			goto cleanup;
		}
		break;
	case AUTHORITY:
		/* same as comments as ALLNODES */
		if (dbi->authority_q == NULL) {
			result = ISC_R_NOTIMPLEMENTED;
			goto cleanup;
		}
		break;
	case FINDZONE:
		/* this is required.  It's the whole point of DLZ! */
		if (dbi->findzone_q == NULL) {
			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
				      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
				      "No query specified for findzone.  "
				      "Findzone requires a query");
			result = ISC_R_FAILURE;
			goto cleanup;
		}
		break;
	case LOOKUP:
		/* this is required.  It's also a major point of DLZ! */
		if (dbi->lookup_q == NULL) {
			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
				      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
				      "No query specified for lookup.  "
				      "Lookup requires a query");
			result = ISC_R_FAILURE;
			goto cleanup;
		}
		break;
	default:
		/*
		 * this should never happen.  If it does, the code is
		 * screwed up!
		 */
		UNEXPECTED_ERROR(__FILE__, __LINE__,
				 "Incorrect query flag passed to "
				 "postgres_get_resultset");
		result = ISC_R_UNEXPECTED;
		goto cleanup;
	}

#if 0
	/* temporary logging message */
	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
		      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
		      "%d checked query", dlz_thread_num);
#endif

	/*
	 * was a zone string passed?  If so, make it safe for use in
	 * queries.
	 */
	if (zone != NULL) {
		dbi->zone = postgres_escape_string(zone);
		if (dbi->zone == NULL) {
			result = ISC_R_NOMEMORY;
			goto cleanup;
		}
	} else {	/* no string passed, set the string pointer to NULL */
		dbi->zone = NULL;
	}

#if 0
	/* temporary logging message */
	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
		      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
		      "%d did zone", dlz_thread_num);
#endif

	/*
	 * was a record string passed?  If so, make it safe for use in
	 * queries.
	 */
	if (record != NULL) {
		dbi->record = postgres_escape_string(record);
		if (dbi->record == NULL) {
			result = ISC_R_NOMEMORY;
			goto cleanup;
		}
	} else {	/* no string passed, set the string pointer to NULL */
		dbi->record = NULL;
	}


#if 0
	/* temporary logging message */
	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
		      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
		      "%d did record", dlz_thread_num);
#endif

	/*
	 * was a client string passed?  If so, make it safe for use in
	 * queries.
	 */
	if (client != NULL) {
		dbi->client = postgres_escape_string(client);
		if (dbi->client == NULL) {
			result = ISC_R_NOMEMORY;
			goto cleanup;
		}
	} else {	/* no string passed, set the string pointer to NULL */
		dbi->client = NULL;
	}

#if 0
	/* temporary logging message */
	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
	DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
		      "%d did client", dlz_thread_num);
#endif

	/*
	 * what type of query are we going to run?
	 * this time we build the actual query to run.
	 */
	switch(query) {
	case ALLNODES:
		querystring = build_querystring(ns_g_mctx, dbi->allnodes_q);
		break;
	case ALLOWXFR:
		querystring = build_querystring(ns_g_mctx, dbi->allowxfr_q);
		break;
	case AUTHORITY:
		querystring = build_querystring(ns_g_mctx, dbi->authority_q);
		break;
	case FINDZONE:
		querystring = build_querystring(ns_g_mctx, dbi->findzone_q);
		break;
	case LOOKUP:
		querystring = build_querystring(ns_g_mctx, dbi->lookup_q);
		break;
	default:
		/*
		 * this should never happen.  If it does, the code is
		 * screwed up!
		 */
		UNEXPECTED_ERROR(__FILE__, __LINE__,
				 "Incorrect query flag passed to "
				 "postgres_get_resultset");
		result = ISC_R_UNEXPECTED;
		goto cleanup;
	}

#if 0
	/* temporary logging message */
	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
		      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
		      "%d built query", dlz_thread_num);
#endif

	/* if the querystring is null, Bummer, outta RAM.  UPGRADE TIME!!!   */
	if (querystring  == NULL) {
		result = ISC_R_NOMEMORY;
		goto cleanup;
	}

#if 0
	/* temporary logging message */
	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
		      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
		      "%d query is '%s'", dlz_thread_num, querystring);
#endif

	/*
	 * output the full query string during debug so we can see
	 * what lame error the query has.
	 */
	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
		      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
		      "\nQuery String: %s\n", querystring);

	/* attempt query up to 3 times. */
	for (j=0; j < 3; j++) {
#if 0
		/* temporary logging message */
		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
			      "%d executing query for %d time",
			      dlz_thread_num, j);
#endif
		/* try to get result set */
		*rs = PQexec((PGconn *)dbi->dbconn, querystring );
		result = ISC_R_SUCCESS;
		/*
		 * if result set is null, reset DB connection, max 3
		 * attempts.
		 */
		for (i=0; *rs == NULL && i < 3; i++) {
#if 0
			/* temporary logging message */
			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
				      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
				      "%d resetting connection",
				      dlz_thread_num);
#endif
			result = ISC_R_FAILURE;
			PQreset((PGconn *) dbi->dbconn);
			/* connection ok, break inner loop */
			if (PQstatus((PGconn *) dbi->dbconn) == CONNECTION_OK)
				break;
		}
		/* result set ok, break outter loop */
		if (PQresultStatus(*rs) == PGRES_TUPLES_OK) {
#if 0
			/* temporary logging message */
			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
				      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
				      "%d rs ok", dlz_thread_num);
#endif
			break;
		} else {
			/* we got a result set object, but it's not right. */
#if 0
			/* temporary logging message */
			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
				      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
				      "%d clearing rs", dlz_thread_num);
#endif
			PQclear(*rs);	/* get rid of it */
			/* in case this was the last attempt */
			result = ISC_R_FAILURE;
		}
	}

 cleanup:
	/* it's always good to cleanup after yourself */

#if 0
	/* temporary logging message */
	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
		      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
		      "%d cleaning up", dlz_thread_num);
#endif

	/* if we couldn't even allocate DBI, just return NULL */
	if (dbi == NULL)
		return ISC_R_FAILURE;

	/* free dbi->zone string */
	if (dbi->zone != NULL)
		isc_mem_free(ns_g_mctx, dbi->zone);

	/* free dbi->record string */
	if (dbi->record != NULL)
		isc_mem_free(ns_g_mctx, dbi->record);

	/* free dbi->client string */
	if (dbi->client != NULL)
		isc_mem_free(ns_g_mctx, dbi->client);

#ifdef ISC_PLATFORM_USETHREADS

#if 0
	/* temporary logging message */
	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
		      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
		      "%d unlocking mutex", dlz_thread_num);
#endif

	/* release the lock so another thread can use this dbi */
	isc_mutex_unlock(&dbi->instance_lock);

#endif /* ISC_PLATFORM_USETHREADS */

	/* release query string */
	if (querystring  != NULL)
		isc_mem_free(ns_g_mctx, querystring );

#if 0
	/* temporary logging message */
	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
		      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
		      "%d returning", dlz_thread_num);
#endif

	/* return result */
	return result;
}
Example #8
0
static int
t_timers5(void) {
	char		*p;
	int		result;
	isc_mem_t	*mctx;
	isc_taskmgr_t	*tmgr;
	unsigned int	workers;
	isc_result_t	isc_result;
	isc_timermgr_t	*timermgr;
	isc_event_t	*event;
	isc_time_t	expires;
	isc_interval_t	interval;

	T5_startflag = 0;
	T5_shutdownflag = 0;
	T5_eventcnt = 0;

	workers = 2;
	p = t_getenv("ISC_TASK_WORKERS");
	if (p != NULL)
		workers = atoi(p);

	mctx = NULL;
	isc_result = isc_mem_create(0, 0, &mctx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_mem_create failed %s\n",
		       isc_result_totext(isc_result));
		return(T_UNRESOLVED);
	}

	isc_result = isc_mutex_init(&T5_mx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_mutex_init failed %s\n",
		       isc_result_totext(isc_result));
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	isc_result = isc_condition_init(&T5_cv);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_condition_init failed %s\n",
		       isc_result_totext(isc_result));
		DESTROYLOCK(&T5_mx);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	tmgr = NULL;
	isc_result = isc_taskmgr_create(mctx, workers, 0, &tmgr);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_taskmgr_create failed %s\n",
		       isc_result_totext(isc_result));
		DESTROYLOCK(&T5_mx);
		(void) isc_condition_destroy(&T5_cv);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	timermgr = NULL;
	isc_result = isc_timermgr_create(mctx, &timermgr);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_timermgr_create failed %s\n",
		       isc_result_totext(isc_result));
		isc_taskmgr_destroy(&tmgr);
		DESTROYLOCK(&T5_mx);
		(void) isc_condition_destroy(&T5_cv);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	T5_task1 = NULL;
	isc_result = isc_task_create(tmgr, 0, &T5_task1);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_task_create failed %s\n",
		       isc_result_totext(isc_result));
		isc_timermgr_destroy(&timermgr);
		isc_taskmgr_destroy(&tmgr);
		DESTROYLOCK(&T5_mx);
		(void) isc_condition_destroy(&T5_cv);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	isc_result = isc_task_onshutdown(T5_task1, t5_shutdown_event, NULL);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_task_onshutdown failed %s\n",
		       isc_result_totext(isc_result));
		isc_timermgr_destroy(&timermgr);
		isc_task_destroy(&T5_task1);
		isc_taskmgr_destroy(&tmgr);
		DESTROYLOCK(&T5_mx);
		(void) isc_condition_destroy(&T5_cv);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	T5_task2 = NULL;
	isc_result = isc_task_create(tmgr, 0, &T5_task2);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_task_create failed %s\n",
		       isc_result_totext(isc_result));
		isc_timermgr_destroy(&timermgr);
		isc_task_destroy(&T5_task1);
		isc_taskmgr_destroy(&tmgr);
		DESTROYLOCK(&T5_mx);
		(void) isc_condition_destroy(&T5_cv);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	isc_result = isc_mutex_lock(&T5_mx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_mutex_lock failed %s\n",
		       isc_result_totext(isc_result));
		isc_timermgr_destroy(&timermgr);
		isc_taskmgr_destroy(&tmgr);
		DESTROYLOCK(&T5_mx);
		(void) isc_condition_destroy(&T5_cv);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	event = isc_event_allocate(mctx, (void *)1 , (isc_eventtype_t)1,
				   t5_start_event, NULL, sizeof(*event));
	isc_task_send(T5_task1, &event);

	isc_time_settoepoch(&expires);
	isc_interval_set(&interval, T5_SECONDS, 0);

	T5_tickertimer = NULL;
	isc_result = isc_timer_create(timermgr, isc_timertype_ticker,
				      &expires, &interval, T5_task1,
				      t5_tick_event, NULL, &T5_tickertimer);

	if (isc_result != ISC_R_SUCCESS) {
		isc_timermgr_destroy(&timermgr);
		(void) isc_condition_signal(&T5_cv);
		(void) isc_mutex_unlock(&T5_mx);
		isc_task_destroy(&T5_task1);
		isc_task_destroy(&T5_task2);
		isc_taskmgr_destroy(&tmgr);
		DESTROYLOCK(&T5_mx);
		(void) isc_condition_destroy(&T5_cv);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	T5_oncetimer = NULL;
	isc_interval_set(&interval, (T5_SECONDS * T5_NTICKS) + 2, 0);
	isc_result = isc_time_nowplusinterval(&expires, &interval);
	if (isc_result != ISC_R_SUCCESS) {
		isc_timer_detach(&T5_tickertimer);
		isc_timermgr_destroy(&timermgr);
		(void)isc_condition_signal(&T5_cv);
		(void)isc_mutex_unlock(&T5_mx);
		isc_task_destroy(&T5_task1);
		isc_task_destroy(&T5_task2);
		isc_taskmgr_destroy(&tmgr);
		DESTROYLOCK(&T5_mx);
		(void) isc_condition_destroy(&T5_cv);
		isc_mem_destroy(&mctx);
		return(T_UNRESOLVED);
	}

	isc_interval_set(&interval, 0, 0);
	isc_result = isc_timer_create(timermgr, isc_timertype_once,
				      &expires, &interval, T5_task2,
				      t5_once_event, NULL, &T5_oncetimer);

	if (isc_result != ISC_R_SUCCESS) {
		isc_timer_detach(&T5_tickertimer);
		isc_timermgr_destroy(&timermgr);
		(void) isc_condition_signal(&T5_cv);
		(void) isc_mutex_unlock(&T5_mx);
		isc_task_destroy(&T5_task1);
		isc_task_destroy(&T5_task2);
		isc_taskmgr_destroy(&tmgr);
		DESTROYLOCK(&T5_mx);
		(void) isc_condition_destroy(&T5_cv);
		isc_mem_destroy(&mctx);
		++T5_nprobs;
		return(T_UNRESOLVED);
	}

	/*
	 * Wait for shutdown processing to complete.
	 */
	while (! T5_shutdownflag) {
		isc_result = isc_condition_wait(&T5_cv, &T5_mx);
		if (isc_result != ISC_R_SUCCESS) {
			t_info("isc_condition_waituntil failed %s\n",
			       isc_result_totext(isc_result));
			++T5_nprobs;
		}
	}

	isc_result = isc_mutex_unlock(&T5_mx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_mutex_unlock failed %s\n",
		       isc_result_totext(isc_result));
		++T5_nprobs;
	}

	if (T5_eventcnt != 1) {
		t_info("processed %d events\n", T5_eventcnt);
		++T5_nfails;
	}

	isc_timer_detach(&T5_tickertimer);
	isc_timer_detach(&T5_oncetimer);
	isc_timermgr_destroy(&timermgr);
	isc_task_destroy(&T5_task1);
	isc_task_destroy(&T5_task2);
	isc_taskmgr_destroy(&tmgr);
	DESTROYLOCK(&T5_mx);
	(void) isc_condition_destroy(&T5_cv);
	isc_mem_destroy(&mctx);

	result = T_UNRESOLVED;

	if ((T5_nfails == 0) && (T5_nprobs == 0))
		result = T_PASS;
	else if (T5_nfails)
		result = T_FAIL;

	return (result);
}
Example #9
0
static void
t_timers_x(isc_timertype_t timertype, isc_time_t *expires,
	   isc_interval_t *interval,
	   void (*action)(isc_task_t *, isc_event_t *))
{
	char		*p;
	isc_mem_t	*mctx;
	isc_taskmgr_t	*tmgr;
	isc_task_t	*task;
	unsigned int	workers;
	isc_result_t	isc_result;
	isc_timermgr_t	*timermgr;

	Tx_eventcnt = 0;
	isc_time_settoepoch(&Tx_endtime);

	workers = 2;
	p = t_getenv("ISC_TASK_WORKERS");
	if (p != NULL)
		workers = atoi(p);

	mctx = NULL;
	isc_result = isc_mem_create(0, 0, &mctx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_mem_create failed %s\n",
		       isc_result_totext(isc_result));
		++Tx_nprobs;
		return;
	}

	isc_result = isc_mutex_init(&Tx_mx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_mutex_init failed %s\n",
		       isc_result_totext(isc_result));
		isc_mem_destroy(&mctx);
		++Tx_nprobs;
		return;
	}

	isc_result = isc_condition_init(&Tx_cv);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_condition_init failed %s\n",
		       isc_result_totext(isc_result));
		DESTROYLOCK(&Tx_mx);
		isc_mem_destroy(&mctx);
		++Tx_nprobs;
		return;
	}

	tmgr = NULL;
	isc_result = isc_taskmgr_create(mctx, workers, 0, &tmgr);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_taskmgr_create failed %s\n",
		       isc_result_totext(isc_result));
		DESTROYLOCK(&Tx_mx);
		(void) isc_condition_destroy(&Tx_cv);
		isc_mem_destroy(&mctx);
		++Tx_nprobs;
		return;
	}

	timermgr = NULL;
	isc_result = isc_timermgr_create(mctx, &timermgr);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_timermgr_create failed %s\n",
		       isc_result_totext(isc_result));
		isc_taskmgr_destroy(&tmgr);
		DESTROYLOCK(&Tx_mx);
		(void) isc_condition_destroy(&Tx_cv);
		isc_mem_destroy(&mctx);
		++Tx_nprobs;
		return;
	}

	isc_result = isc_mutex_lock(&Tx_mx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_mutex_lock failed %s\n",
		       isc_result_totext(isc_result));
		isc_timermgr_destroy(&timermgr);
		isc_taskmgr_destroy(&tmgr);
		DESTROYLOCK(&Tx_mx);
		(void) isc_condition_destroy(&Tx_cv);
		isc_mem_destroy(&mctx);
		++Tx_nprobs;
		return;
	}

	task = NULL;
	isc_result = isc_task_create(tmgr, 0, &task);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_task_create failed %s\n",
		       isc_result_totext(isc_result));
		isc_timermgr_destroy(&timermgr);
		isc_taskmgr_destroy(&tmgr);
		DESTROYLOCK(&Tx_mx);
		(void) isc_condition_destroy(&Tx_cv);
		isc_mem_destroy(&mctx);
		++Tx_nprobs;
		return;
	}

	isc_result = isc_task_onshutdown(task, tx_sde, NULL);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_task_onshutdown failed %s\n",
		       isc_result_totext(isc_result));
		isc_timermgr_destroy(&timermgr);
		isc_task_destroy(&task);
		isc_taskmgr_destroy(&tmgr);
		DESTROYLOCK(&Tx_mx);
		(void) isc_condition_destroy(&Tx_cv);
		isc_mem_destroy(&mctx);
		++Tx_nprobs;
		return;
	}

	isc_result = isc_time_now(&Tx_lasttime);
	if (isc_result != ISC_R_SUCCESS) {
		isc_timermgr_destroy(&timermgr);
		isc_task_destroy(&task);
		isc_taskmgr_destroy(&tmgr);
		DESTROYLOCK(&Tx_mx);
		(void) isc_condition_destroy(&Tx_cv);
		isc_mem_destroy(&mctx);
		++Tx_nprobs;
		return;
	}

	Tx_timer = NULL;
	isc_result = isc_timer_create(timermgr, timertype, expires, interval,
				      task, action, (void *)timertype,
				      &Tx_timer);

	if (isc_result != ISC_R_SUCCESS) {
		isc_timermgr_destroy(&timermgr);
		isc_task_destroy(&task);
		isc_taskmgr_destroy(&tmgr);
		DESTROYLOCK(&Tx_mx);
		(void) isc_condition_destroy(&Tx_cv);
		isc_mem_destroy(&mctx);
		++Tx_nprobs;
		return;
	}

	/*
	 * Wait for shutdown processing to complete.
	 */
	while (Tx_eventcnt != Tx_nevents) {
		isc_result = isc_condition_wait(&Tx_cv, &Tx_mx);
		if (isc_result != ISC_R_SUCCESS) {
			t_info("isc_condition_waituntil failed %s\n",
			       isc_result_totext(isc_result));
			++Tx_nprobs;
		}
	}

	isc_result = isc_mutex_unlock(&Tx_mx);
	if (isc_result != ISC_R_SUCCESS) {
		t_info("isc_mutex_unlock failed %s\n",
		       isc_result_totext(isc_result));
		++Tx_nprobs;
	}

	isc_task_detach(&task);
	isc_taskmgr_destroy(&tmgr);
	isc_timermgr_destroy(&timermgr);
	DESTROYLOCK(&Tx_mx);
	(void) isc_condition_destroy(&Tx_cv);
	isc_mem_destroy(&mctx);

}
static isc_result_t
odbc_process_rs(dns_sdlzlookup_t *lookup, dbinstance_t *dbi)
{


	isc_result_t result;
	SQLSMALLINT fields;
	SQLHSTMT  *stmnt;
	char *ttl_s;
	char *type;
	char *data;
	char *endp;
	int ttl;

	REQUIRE(dbi != NULL);

	stmnt = ((odbc_db_t *) (dbi->dbconn))->stmnt;

	/* get number of columns */
	if (!sqlOK(SQLNumResultCols(stmnt, &fields))) {
		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
			      "Odbc driver unable to process result set");
		result = ISC_R_FAILURE;
		goto process_rs_cleanup;
	}

	/* get things ready for processing */
	result = ISC_R_FAILURE;

	while (sqlOK(SQLFetch(stmnt))) {

		/* set to null for next pass through */
		data = type = ttl_s = NULL;

		switch(fields) {
		case 1:
			/*
			 * one column in rs, it's the data field.  use
			 * default type of A record, and default TTL
			 * of 86400.  attempt to get data, & tell bind
			 * about it.
			 */
			if ((result = odbc_getField(stmnt, 1,
						    &data)) == ISC_R_SUCCESS) {
				result = dns_sdlz_putrr(lookup, "a",
							86400, data);
			}
			break;
		case 2:
			/*
			 * two columns, data field, and data type.
			 * use default TTL of 86400.  attempt to get
			 * DNS type & data, then tell bind about it.
			 */
			if ((result = odbc_getField(stmnt, 1,
						    &type)) == ISC_R_SUCCESS &&
			    (result = odbc_getField(stmnt, 2,
						    &data)) == ISC_R_SUCCESS) {
				result = dns_sdlz_putrr(lookup, type,
							86400, data);
			}
			break;
		default:
			/*
			 * 3 fields or more, concatenate the last ones
			 * together.  attempt to get DNS ttl, type,
			 * data then tell Bind about them.
			 */
			if ((result = odbc_getField(stmnt, 1, &ttl_s))
				== ISC_R_SUCCESS &&
			    (result = odbc_getField(stmnt, 2, &type))
				== ISC_R_SUCCESS &&
			    (result = odbc_getManyFields(stmnt, 3,
							 fields, &data))
				== ISC_R_SUCCESS) {
				/* try to convert ttl string to int */
				ttl = strtol(ttl_s, &endp, 10);
				/* failure converting ttl. */
				if (*endp != '\0' || ttl < 0) {
					isc_log_write(dns_lctx,
						      DNS_LOGCATEGORY_DATABASE,
						      DNS_LOGMODULE_DLZ,
						      ISC_LOG_ERROR,
						      "Odbc driver ttl must "
						      "be a postive number");
					result = ISC_R_FAILURE;
				} else {
					/*
					 * successful converting TTL,
					 * tell Bind everything
					 */
					result = dns_sdlz_putrr(lookup, type,
								ttl, data);
				}
			} /* closes bid if () */
		} /* closes switch(fields) */

		/* clean up mem */
		if (ttl_s != NULL)
			isc_mem_free(ns_g_mctx, ttl_s);
		if (type != NULL)
			isc_mem_free(ns_g_mctx, type);
		if (data != NULL)
			isc_mem_free(ns_g_mctx, data);

		/* I sure hope we were successful */
		if (result != ISC_R_SUCCESS) {
			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
				      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
				      "dns_sdlz_putrr returned error. "
				      "Error code was: %s",
				      isc_result_totext(result));
			result = ISC_R_FAILURE;
			goto process_rs_cleanup;
		}
	} /* closes while loop */

 process_rs_cleanup:

	/* close cursor */
	SQLCloseCursor(((odbc_db_t *) (dbi->dbconn))->stmnt);

#ifdef ISC_PLATFORM_USETHREADS

	/* free lock on dbi so someone else can use it. */
	isc_mutex_unlock(&dbi->instance_lock);

#endif

	return result;
}
static isc_result_t
odbc_get_resultset(const char *zone, const char *record,
		   const char *client, unsigned int query,
		   void *dbdata, dbinstance_t **r_dbi)
{

	isc_result_t result;
	dbinstance_t *dbi = NULL;
	char *querystring = NULL;
	unsigned int j = 0;
	SQLRETURN sqlRes;

	REQUIRE(*r_dbi == NULL);

	/* get db instance / connection */
#ifdef ISC_PLATFORM_USETHREADS

	/* find an available DBI from the list */
	dbi = odbc_find_avail_conn(((odbc_instance_t *) dbdata)->db);

#else /* ISC_PLATFORM_USETHREADS */

	/*
	 * only 1 DBI - no need to lock instance lock either
	 * only 1 thread in the whole process, no possible contention.
	 */
	dbi =  (dbinstance_t *) ((odbc_instance_t *) dbdata)->db;

#endif /* ISC_PLATFORM_USETHREADS */

	/* if DBI is null, can't do anything else */
	if (dbi == NULL) {
		result = ISC_R_FAILURE;
		goto cleanup;
	}

	/* what type of query are we going to run? */
	switch(query) {
	case ALLNODES:
		/*
		 * if the query was not passed in from the config file
		 * then we can't run it.  return not_implemented, so
		 * it's like the code for that operation was never
		 * built into the driver.... AHHH flexibility!!!
		 */
		if (dbi->allnodes_q == NULL) {
			result = ISC_R_NOTIMPLEMENTED;
			goto cleanup;
		}
		break;
	case ALLOWXFR:
		/* same as comments as ALLNODES */
		if (dbi->allowxfr_q == NULL) {
			result = ISC_R_NOTIMPLEMENTED;
			goto cleanup;
		}
		break;
	case AUTHORITY:
		/* same as comments as ALLNODES */
		if (dbi->authority_q == NULL) {
			result = ISC_R_NOTIMPLEMENTED;
			goto cleanup;
		}
		break;
	case FINDZONE:
		/* this is required.  It's the whole point of DLZ! */
		if (dbi->findzone_q == NULL) {
			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
				      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
				      "No query specified for findzone.  "
				      "Findzone requires a query");
			result = ISC_R_FAILURE;
			goto cleanup;
		}
		break;
	case LOOKUP:
		/* this is required.  It's also a major point of DLZ! */
		if (dbi->lookup_q == NULL) {
			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
				      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
				      "No query specified for lookup.  "
				      "Lookup requires a query");
			result = ISC_R_FAILURE;
			goto cleanup;
		}
		break;
	default:
		/*
		 * this should never happen.  If it does, the code is
		 * screwed up!
		 */
		UNEXPECTED_ERROR(__FILE__, __LINE__,
				 "Incorrect query flag passed to "
				 "odbc_get_resultset");
		result = ISC_R_UNEXPECTED;
		goto cleanup;
	}


	/*
	 * was a zone string passed?  If so, make it safe for use in
	 * queries.
	 */
	if (zone != NULL) {
		dbi->zone = odbc_escape_string(zone);
		if (dbi->zone == NULL) {
			result = ISC_R_NOMEMORY;
			goto cleanup;
		}
	} else {	/* no string passed, set the string pointer to NULL */
		dbi->zone = NULL;
	}

	/*
	 * was a record string passed?  If so, make it safe for use in
	 * queries.
	 */
	if (record != NULL) {
		dbi->record = odbc_escape_string(record);
		if (dbi->record == NULL) {
			result = ISC_R_NOMEMORY;
			goto cleanup;
		}
	} else {	/* no string passed, set the string pointer to NULL */
		dbi->record = NULL;
	}

	/*
	 * was a client string passed?  If so, make it safe for use in
	 * queries.
	 */
	if (client != NULL) {
		dbi->client = odbc_escape_string(client);
		if (dbi->client == NULL) {
			result = ISC_R_NOMEMORY;
			goto cleanup;
		}
	} else {	/* no string passed, set the string pointer to NULL */
		dbi->client = NULL;
	}

	/*
	 * what type of query are we going to run?
	 * this time we build the actual query to run.
	 */
	switch(query) {
	case ALLNODES:
		querystring = build_querystring(ns_g_mctx, dbi->allnodes_q);
		break;
	case ALLOWXFR:
		querystring = build_querystring(ns_g_mctx, dbi->allowxfr_q);
		break;
	case AUTHORITY:
		querystring = build_querystring(ns_g_mctx, dbi->authority_q);
		break;
	case FINDZONE:
		querystring = build_querystring(ns_g_mctx, dbi->findzone_q);
		break;
	case LOOKUP:
		querystring = build_querystring(ns_g_mctx, dbi->lookup_q);
		break;
	default:
		/*
		 * this should never happen.  If it does, the code is
		 * screwed up!
		 */
		UNEXPECTED_ERROR(__FILE__, __LINE__,
				 "Incorrect query flag passed to "
				 "odbc_get_resultset");
		result = ISC_R_UNEXPECTED;
		goto cleanup;
	}

	/* if the querystring is null, Bummer, outta RAM.  UPGRADE TIME!!!   */
	if (querystring  == NULL) {
		result = ISC_R_NOMEMORY;
		goto cleanup;
	}

	/* output the full query string during debug so we can see */
	/* what lame error the query has. */
	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
		      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
		      "\nQuery String: %s\n", querystring);

	/* attempt query up to 3 times. */
	for (j=0; j < 3; j++) {
		/* try to get result set */
		sqlRes = SQLExecDirect(((odbc_db_t *) dbi->dbconn)->stmnt,
				       (SQLCHAR *) querystring,
				       (SQLINTEGER) strlen(querystring));

		/* if error, reset DB connection */
		if (!sqlOK(sqlRes)) {
			/* close cursor */
			SQLCloseCursor(((odbc_db_t *) dbi->dbconn)->stmnt);
			/* attempt to reconnect */
			result = odbc_connect((odbc_instance_t *) dbdata,
					      (odbc_db_t **) &(dbi->dbconn));
			/* check if we reconnected */
			if (result != ISC_R_SUCCESS)
				break;
			/* incase this is the last time through the loop */
			result = ISC_R_FAILURE;
		} else {
			result = ISC_R_SUCCESS;
			/* return dbi */
			*r_dbi = dbi;
			/* result set ok, break loop */
			break;
		}
	}	/* end for loop */

 cleanup:	/* it's always good to cleanup after yourself */

		/* if we couldn't even allocate DBI, just return NULL */
	if (dbi == NULL)
		return ISC_R_FAILURE;

	/* free dbi->zone string */
	if (dbi->zone != NULL)
		isc_mem_free(ns_g_mctx, dbi->zone);

	/* free dbi->record string */
	if (dbi->record != NULL)
		isc_mem_free(ns_g_mctx, dbi->record);

	/* free dbi->client string */
	if (dbi->client != NULL)
		isc_mem_free(ns_g_mctx, dbi->client);

#ifdef ISC_PLATFORM_USETHREADS

	/* if we are done using this dbi, release the lock */
	if (result != ISC_R_SUCCESS)
		isc_mutex_unlock(&dbi->instance_lock);

#endif /* ISC_PLATFORM_USETHREADS */

	/* release query string */
	if (querystring  != NULL)
		isc_mem_free(ns_g_mctx, querystring );

	/* return result */
	return result;

}
static isc_result_t
odbc_allnodes(const char *zone, void *driverarg, void *dbdata,
	      dns_sdlzallnodes_t *allnodes)
{

	isc_result_t result;
	dbinstance_t *dbi = NULL;
	SQLHSTMT  *stmnt;
	SQLSMALLINT fields;
	char *data;
	char *type;
	char *ttl_s;
	int ttl;
	char *host;
	char *endp;

	UNUSED(driverarg);

	/* run the query and get the result set from the database. */
	result = odbc_get_resultset(zone, NULL, NULL, ALLNODES, dbdata, &dbi);

	/* if we get "not implemented", send it along */
	if (result == ISC_R_NOTIMPLEMENTED)
		return result;

	/* if we didn't get a result set, log an err msg. */
	if (result != ISC_R_SUCCESS) {
		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
			      "Odbc driver unable to return "
			      "result set for all nodes query");
		return (ISC_R_FAILURE);
	}

	stmnt = ((odbc_db_t *) (dbi->dbconn))->stmnt;

	/* get number of columns */
	if (!sqlOK(SQLNumResultCols(stmnt, &fields))) {
		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
			      "Odbc driver unable to process result set");
		result = ISC_R_FAILURE;
		goto allnodes_cleanup;
	}

	if (fields < 4) {	/* gotta have at least 4 columns */
		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
			      "Odbc driver too few fields returned by "
			      "all nodes query");
		result = ISC_R_FAILURE;
		goto allnodes_cleanup;
	}

	/* get things ready for processing */
	result = ISC_R_FAILURE;

	while (sqlOK(SQLFetch(stmnt))) {

		/* set to null for next pass through */
		data = host = type = ttl_s = NULL;

		/*
		 * attempt to get DNS ttl, type, host, data then tell
		 * Bind about them
		 */
		if ((result = odbc_getField(stmnt, 1,
					    &ttl_s)) == ISC_R_SUCCESS &&
		    (result = odbc_getField(stmnt, 2,
					    &type)) == ISC_R_SUCCESS &&
		    (result = odbc_getField(stmnt, 3,
					    &host)) == ISC_R_SUCCESS &&
		    (result = odbc_getManyFields(stmnt, 4, fields,
						 &data)) == ISC_R_SUCCESS) {
			/* convert ttl string to int */
			ttl = strtol(ttl_s, &endp, 10);
			/* failure converting ttl. */
			if (*endp != '\0' || ttl < 0) {
				isc_log_write(dns_lctx,
					      DNS_LOGCATEGORY_DATABASE,
					      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
					      "Odbc driver ttl must be "
					      "a postive number");
				result = ISC_R_FAILURE;
			} else {
				/* successful converting TTL, tell Bind  */
				result = dns_sdlz_putnamedrr(allnodes, host,
							     type, ttl, data);
			}
		} /* closes big if () */

		/* clean up mem */
		if (ttl_s != NULL)
			isc_mem_free(ns_g_mctx, ttl_s);
		if (type != NULL)
			isc_mem_free(ns_g_mctx, type);
		if (host != NULL)
			isc_mem_free(ns_g_mctx, host);
		if (data != NULL)
			isc_mem_free(ns_g_mctx, data);

		/* if we weren't successful, log err msg */
		if (result != ISC_R_SUCCESS) {
			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
				      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
				      "dns_sdlz_putnamedrr returned error. "
				      "Error code was: %s",
				      isc_result_totext(result));
			result = ISC_R_FAILURE;
			goto allnodes_cleanup;
		}
	} /* closes while loop */

 allnodes_cleanup:

	/* close cursor */
	SQLCloseCursor(((odbc_db_t *) (dbi->dbconn))->stmnt);

#ifdef ISC_PLATFORM_USETHREADS

	/* free lock on dbi so someone else can use it. */
	isc_mutex_unlock(&dbi->instance_lock);

#endif

	return result;
}
Example #13
0
/*%
 * This function is the real core of the driver.   Zone, record
 * and client strings are passed in (or NULL is passed if the
 * string is not available).  The type of query we want to run
 * is indicated by the query flag, and the dbdata object is passed
 * passed in to.  dbdata really holds either:
 *		1) a list of database instances (in multithreaded mode) OR
 *		2) a single database instance (in single threaded mode)
 * The function will construct the query and obtain an available
 * database instance (DBI).  It will then run the query and hopefully
 * obtain a result set.
 */
static isc_result_t
ldap_get_results(const char *zone, const char *record,
		 const char *client, unsigned int query,
		 void *dbdata, void *ptr)
{
	isc_result_t result;
	dbinstance_t *dbi = NULL;
	char *querystring = NULL;
	LDAPURLDesc *ldap_url = NULL;
	int ldap_result = 0;
	LDAPMessage *ldap_msg = NULL;
	int i;
	int entries;

	/* get db instance / connection */
#ifdef ISC_PLATFORM_USETHREADS

	/* find an available DBI from the list */
	dbi = ldap_find_avail_conn((db_list_t *)
				   ((ldap_instance_t *)dbdata)->db);

#else /* ISC_PLATFORM_USETHREADS */

	/*
	 * only 1 DBI - no need to lock instance lock either
	 * only 1 thread in the whole process, no possible contention.
	 */
	dbi =  (dbinstance_t *) ((ldap_instance_t *)dbdata)->db;

#endif /* ISC_PLATFORM_USETHREADS */

	/* if DBI is null, can't do anything else */
	if (dbi == NULL)
		return (ISC_R_FAILURE);

	/* set fields */
	if (zone != NULL) {
		dbi->zone = isc_mem_strdup(ns_g_mctx, zone);
		if (dbi->zone == NULL) {
			result = ISC_R_NOMEMORY;
			goto cleanup;
		}
	} else {
		dbi->zone = NULL;
	}
	if (record != NULL) {
		dbi->record = isc_mem_strdup(ns_g_mctx, record);
		if (dbi->record == NULL) {
			result = ISC_R_NOMEMORY;
			goto cleanup;
		}
	} else {
		dbi->record = NULL;
	}
	if (client != NULL) {
		dbi->client = isc_mem_strdup(ns_g_mctx, client);
		if (dbi->client == NULL) {
			result = ISC_R_NOMEMORY;
			goto cleanup;
		}
	} else {
		dbi->client = NULL;
	}

	/* what type of query are we going to run? */
	switch(query) {
	case ALLNODES:
		/*
		 * if the query was not passed in from the config file
		 * then we can't run it.  return not_implemented, so
		 * it's like the code for that operation was never
		 * built into the driver.... AHHH flexibility!!!
		 */
		if (dbi->allnodes_q == NULL) {
			result = ISC_R_NOTIMPLEMENTED;
			goto cleanup;
		} else {
			querystring = build_querystring(ns_g_mctx,
			dbi->allnodes_q);
		}
		break;
	case ALLOWXFR:
		/* same as comments as ALLNODES */
		if (dbi->allowxfr_q == NULL) {
			result = ISC_R_NOTIMPLEMENTED;
			goto cleanup;
		} else {
			querystring = build_querystring(ns_g_mctx,
			dbi->allowxfr_q);
		}
		break;
	case AUTHORITY:
		/* same as comments as ALLNODES */
		if (dbi->authority_q == NULL) {
			result = ISC_R_NOTIMPLEMENTED;
			goto cleanup;
		} else {
			querystring = build_querystring(ns_g_mctx,
			dbi->authority_q);
		}
		break;
	case FINDZONE:
		/* this is required.  It's the whole point of DLZ! */
		if (dbi->findzone_q == NULL) {
			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
				      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
				      "No query specified for findzone.  "
				      "Findzone requires a query");
			result = ISC_R_FAILURE;
			goto cleanup;
		} else {
			querystring = build_querystring(ns_g_mctx,
			dbi->findzone_q);
		}
		break;
	case LOOKUP:
		/* this is required.  It's also a major point of DLZ! */
		if (dbi->lookup_q == NULL) {
			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
				      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
				      "No query specified for lookup.  "
				      "Lookup requires a query");
			result = ISC_R_FAILURE;
			goto cleanup;
		} else {
			querystring = build_querystring(ns_g_mctx,
							dbi->lookup_q);
		}
		break;
	default:
		/*
		 * this should never happen.  If it does, the code is
		 * screwed up!
		 */
		UNEXPECTED_ERROR(__FILE__, __LINE__,
				 "Incorrect query flag passed to "
				 "ldap_get_results");
		result = ISC_R_UNEXPECTED;
		goto cleanup;
	}

	/* if the querystring is null, Bummer, outta RAM.  UPGRADE TIME!!!   */
	if (querystring  == NULL) {
		result = ISC_R_NOMEMORY;
		goto cleanup;
	}

	/*
	 * output the full query string during debug so we can see
	 * what lame error the query has.
	 */
	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
		      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
		      "\nQuery String: %s\n", querystring);

        /* break URL down into it's component parts, if error cleanup */
	ldap_result = ldap_url_parse(querystring, &ldap_url);
	if (ldap_result != LDAP_SUCCESS || ldap_url == NULL) {
		result = ISC_R_FAILURE;
		goto cleanup;
	}

	for (i = 0; i < 3; i++) {

		/*
		 * dbi->dbconn may be null if trying to reconnect on a
		 * previous query failed.
		 */
		if (dbi->dbconn == NULL) {
			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
				      DNS_LOGMODULE_DLZ, ISC_LOG_INFO,
				      "LDAP driver attempting to re-connect");

			result = dlz_ldap_connect((ldap_instance_t *) dbdata,
						  dbi);
			if (result != ISC_R_SUCCESS) {
				result = ISC_R_FAILURE;
				continue;
			}
		}

		/* perform ldap search syncronously */
		ldap_result = ldap_search_s((LDAP *) dbi->dbconn,
					    ldap_url->lud_dn,
					    ldap_url->lud_scope,
					    ldap_url->lud_filter,
					    ldap_url->lud_attrs, 0, &ldap_msg);

		/*
		 * check return code.  No such object is ok, just
		 * didn't find what we wanted
		 */
		switch(ldap_result) {
		case LDAP_NO_SUCH_OBJECT:
    			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
				      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
				      "No object found matching "
				      "query requirements");
			result = ISC_R_NOTFOUND;
			goto cleanup;
			break;
		case LDAP_SUCCESS:	/* on success do nothing */
			result = ISC_R_SUCCESS;
			i = 3;
			break;
		case LDAP_SERVER_DOWN:
			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
				      DNS_LOGMODULE_DLZ, ISC_LOG_INFO,
				      "LDAP driver attempting to re-connect");
			result = dlz_ldap_connect((ldap_instance_t *) dbdata,
						  dbi);
			if (result != ISC_R_SUCCESS)
				result = ISC_R_FAILURE;
			break;
		default:
			/*
			 * other errors not ok.  Log error message and
			 * get out
			 */
    			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
				      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
				      "LDAP error: %s",
				      ldap_err2string(ldap_result));
			result = ISC_R_FAILURE;
			goto cleanup;
			break;
		} /* close switch(ldap_result) */
	} /* end for (int i = 0 i < 3; i++) */

	if (result != ISC_R_SUCCESS)
		goto cleanup;

	switch(query) {
	case ALLNODES:
		result = ldap_process_results((LDAP *) dbi->dbconn, ldap_msg,
					      ldap_url->lud_attrs,
					      ptr, isc_boolean_true);
		break;
	case AUTHORITY:
	case LOOKUP:
		result = ldap_process_results((LDAP *) dbi->dbconn, ldap_msg,
					      ldap_url->lud_attrs,
					      ptr, isc_boolean_false);
		break;
	case ALLOWXFR:
		entries = ldap_count_entries((LDAP *) dbi->dbconn, ldap_msg);
		if (entries == 0)
			result = ISC_R_NOPERM;
		else if (entries > 0)
			result = ISC_R_SUCCESS;
		else
			result = ISC_R_FAILURE;
		break;
	case FINDZONE:
		entries = ldap_count_entries((LDAP *) dbi->dbconn, ldap_msg);
		if (entries == 0)
			result = ISC_R_NOTFOUND;
		else if (entries > 0)
			result = ISC_R_SUCCESS;
		else
			result = ISC_R_FAILURE;
		break;
	default:
		/*
		 * this should never happen.  If it does, the code is
		 * screwed up!
		 */
		UNEXPECTED_ERROR(__FILE__, __LINE__,
				 "Incorrect query flag passed to "
				 "ldap_get_results");
		result = ISC_R_UNEXPECTED;
	}

 cleanup:
	/* it's always good to cleanup after yourself */

        /* if we retrieved results, free them */
	if (ldap_msg != NULL)
		ldap_msgfree(ldap_msg);

	if (ldap_url != NULL)
		ldap_free_urldesc(ldap_url);

	/* cleanup */
	if (dbi->zone != NULL)
		isc_mem_free(ns_g_mctx, dbi->zone);
	if (dbi->record != NULL)
		isc_mem_free(ns_g_mctx, dbi->record);
	if (dbi->client != NULL)
		isc_mem_free(ns_g_mctx, dbi->client);

#ifdef ISC_PLATFORM_USETHREADS

	/* release the lock so another thread can use this dbi */
	isc_mutex_unlock(&dbi->instance_lock);

#endif /* ISC_PLATFORM_USETHREADS */

        /* release query string */
	if (querystring  != NULL)
		isc_mem_free(ns_g_mctx, querystring );

	/* return result */
	return (result);
}