1/*	$NetBSD: dnstest.c,v 1.1.1.1.4.1 2012/06/06 18:18:18 bouyer Exp $	*/
2
3/*
4 * Copyright (C) 2011, 2012  Internet Systems Consortium, Inc. ("ISC")
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
17 */
18
19/* Id */
20
21/*! \file */
22
23#include <config.h>
24
25#include <time.h>
26#include <unistd.h>
27
28#include <isc/app.h>
29#include <isc/buffer.h>
30#include <isc/entropy.h>
31#include <isc/hash.h>
32#include <isc/mem.h>
33#include <isc/os.h>
34#include <isc/string.h>
35#include <isc/socket.h>
36#include <isc/task.h>
37#include <isc/timer.h>
38#include <isc/util.h>
39
40#include <dns/db.h>
41#include <dns/fixedname.h>
42#include <dns/log.h>
43#include <dns/name.h>
44#include <dns/result.h>
45#include <dns/view.h>
46#include <dns/zone.h>
47
48#include <dst/dst.h>
49
50#include "dnstest.h"
51
52isc_mem_t *mctx = NULL;
53isc_entropy_t *ectx = NULL;
54isc_log_t *lctx = NULL;
55isc_taskmgr_t *taskmgr = NULL;
56isc_task_t *maintask = NULL;
57isc_timermgr_t *timermgr = NULL;
58isc_socketmgr_t *socketmgr = NULL;
59dns_zonemgr_t *zonemgr = NULL;
60isc_boolean_t app_running = ISC_FALSE;
61int ncpus;
62
63static isc_boolean_t hash_active = ISC_FALSE, dst_active = ISC_FALSE;
64
65/*
66 * Logging categories: this needs to match the list in bin/named/log.c.
67 */
68static isc_logcategory_t categories[] = {
69		{ "",                0 },
70		{ "client",          0 },
71		{ "network",         0 },
72		{ "update",          0 },
73		{ "queries",         0 },
74		{ "unmatched",       0 },
75		{ "update-security", 0 },
76		{ "query-errors",    0 },
77		{ NULL,              0 }
78};
79
80static void
81cleanup_managers() {
82	if (app_running)
83		isc_app_finish();
84	if (socketmgr != NULL)
85		isc_socketmgr_destroy(&socketmgr);
86	if (maintask != NULL)
87		isc_task_destroy(&maintask);
88	if (taskmgr != NULL)
89		isc_taskmgr_destroy(&taskmgr);
90	if (timermgr != NULL)
91		isc_timermgr_destroy(&timermgr);
92}
93
94static isc_result_t
95create_managers() {
96	isc_result_t result;
97#ifdef ISC_PLATFORM_USETHREADS
98	ncpus = isc_os_ncpus();
99#else
100	ncpus = 1;
101#endif
102
103	CHECK(isc_taskmgr_create(mctx, ncpus, 0, &taskmgr));
104	CHECK(isc_timermgr_create(mctx, &timermgr));
105	CHECK(isc_socketmgr_create(mctx, &socketmgr));
106	CHECK(isc_task_create(taskmgr, 0, &maintask));
107	return (ISC_R_SUCCESS);
108
109  cleanup:
110	cleanup_managers();
111	return (result);
112}
113
114isc_result_t
115dns_test_begin(FILE *logfile, isc_boolean_t start_managers) {
116	isc_result_t result;
117
118	if (start_managers)
119		CHECK(isc_app_start());
120	isc_mem_debugging |= ISC_MEM_DEBUGRECORD;
121	CHECK(isc_mem_create(0, 0, &mctx));
122	CHECK(isc_entropy_create(mctx, &ectx));
123
124	CHECK(isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE));
125	hash_active = ISC_TRUE;
126
127	CHECK(dst_lib_init(mctx, ectx, ISC_ENTROPY_BLOCKING));
128	dst_active = ISC_TRUE;
129
130	if (logfile != NULL) {
131		isc_logdestination_t destination;
132		isc_logconfig_t *logconfig = NULL;
133
134		CHECK(isc_log_create(mctx, &lctx, &logconfig));
135		isc_log_registercategories(lctx, categories);
136		isc_log_setcontext(lctx);
137		dns_log_init(lctx);
138		dns_log_setcontext(lctx);
139
140		destination.file.stream = logfile;
141		destination.file.name = NULL;
142		destination.file.versions = ISC_LOG_ROLLNEVER;
143		destination.file.maximum_size = 0;
144		CHECK(isc_log_createchannel(logconfig, "stderr",
145					    ISC_LOG_TOFILEDESC,
146					    ISC_LOG_DYNAMIC,
147					    &destination, 0));
148		CHECK(isc_log_usechannel(logconfig, "stderr", NULL, NULL));
149	}
150
151	dns_result_register();
152
153	if (start_managers)
154		CHECK(create_managers());
155
156	/*
157	 * atf-run changes us to a /tmp directory, so tests
158	 * that access test data files must first chdir to the proper
159	 * location.
160	 */
161	if (chdir(TESTS) == -1)
162		CHECK(ISC_R_FAILURE);
163
164	return (ISC_R_SUCCESS);
165
166  cleanup:
167	dns_test_end();
168	return (result);
169}
170
171void
172dns_test_end() {
173	if (lctx != NULL)
174		isc_log_destroy(&lctx);
175	if (dst_active) {
176		dst_lib_destroy();
177		dst_active = ISC_FALSE;
178	}
179	if (hash_active) {
180		isc_hash_destroy();
181		hash_active = ISC_FALSE;
182	}
183	if (ectx != NULL)
184		isc_entropy_detach(&ectx);
185
186	cleanup_managers();
187
188	if (mctx != NULL)
189		isc_mem_destroy(&mctx);
190}
191
192/*
193 * Create a zone with origin 'name', return a pointer to the zone object in
194 * 'zonep'.  If 'view' is set, add the zone to that view; otherwise, create
195 * a new view for the purpose.
196 *
197 * If the created view is going to be needed by the caller subsequently,
198 * then 'keepview' should be set to true; this will prevent the view
199 * from being detached.  In this case, the caller is responsible for
200 * detaching the view.
201 */
202isc_result_t
203dns_test_makezone(const char *name, dns_zone_t **zonep, dns_view_t *view,
204		  isc_boolean_t keepview)
205{
206	isc_result_t result;
207	dns_zone_t *zone = NULL;
208	isc_buffer_t buffer;
209	dns_fixedname_t fixorigin;
210	dns_name_t *origin;
211
212	if (view == NULL)
213		CHECK(dns_view_create(mctx, dns_rdataclass_in, "view", &view));
214	else if (!keepview)
215		keepview = ISC_TRUE;
216
217	CHECK(dns_zone_create(&zone, mctx));
218
219	isc_buffer_init(&buffer, name, strlen(name));
220	isc_buffer_add(&buffer, strlen(name));
221	dns_fixedname_init(&fixorigin);
222	origin = dns_fixedname_name(&fixorigin);
223	CHECK(dns_name_fromtext(origin, &buffer, dns_rootname, 0, NULL));
224	CHECK(dns_zone_setorigin(zone, origin));
225	dns_zone_setview(zone, view);
226	dns_zone_settype(zone, dns_zone_master);
227	dns_zone_setclass(zone, view->rdclass);
228	dns_view_addzone(view, zone);
229
230	if (!keepview)
231		dns_view_detach(&view);
232
233	*zonep = zone;
234
235	return (ISC_R_SUCCESS);
236
237  cleanup:
238	if (zone != NULL)
239		dns_zone_detach(&zone);
240	if (view != NULL)
241		dns_view_detach(&view);
242	return (result);
243}
244
245isc_result_t
246dns_test_setupzonemgr() {
247	isc_result_t result;
248	REQUIRE(zonemgr == NULL);
249
250	result = dns_zonemgr_create(mctx, taskmgr, timermgr, socketmgr,
251				    &zonemgr);
252	return (result);
253}
254
255isc_result_t
256dns_test_managezone(dns_zone_t *zone) {
257	isc_result_t result;
258	REQUIRE(zonemgr != NULL);
259
260	result = dns_zonemgr_setsize(zonemgr, 1);
261	if (result != ISC_R_SUCCESS)
262		return (result);
263
264	result = dns_zonemgr_managezone(zonemgr, zone);
265	return (result);
266}
267
268void
269dns_test_releasezone(dns_zone_t *zone) {
270	REQUIRE(zonemgr != NULL);
271	dns_zonemgr_releasezone(zonemgr, zone);
272}
273
274void
275dns_test_closezonemgr() {
276	REQUIRE(zonemgr != NULL);
277
278	dns_zonemgr_shutdown(zonemgr);
279	dns_zonemgr_detach(&zonemgr);
280}
281
282/*
283 * Sleep for 'usec' microseconds.
284 */
285void
286dns_test_nap(isc_uint32_t usec) {
287#ifdef HAVE_NANOSLEEP
288	struct timespec ts;
289
290	ts.tv_sec = usec / 1000000;
291	ts.tv_nsec = (usec % 1000000) * 1000;
292	nanosleep(&ts, NULL);
293#elif HAVE_USLEEP
294	usleep(usec);
295#else
296	/*
297	 * No fractional-second sleep function is available, so we
298	 * round up to the nearest second and sleep instead
299	 */
300	sleep((usec / 1000000) + 1);
301#endif
302}
303
304isc_result_t
305dns_test_loaddb(dns_db_t **db, dns_dbtype_t dbtype, const char *origin,
306		const char *testfile)
307{
308	isc_result_t		result;
309	dns_fixedname_t		fixed;
310	dns_name_t		*name;
311
312	dns_fixedname_init(&fixed);
313	name = dns_fixedname_name(&fixed);
314
315	result = dns_name_fromstring(name, origin, 0, NULL);
316	if (result != ISC_R_SUCCESS)
317		return(result);
318
319	result = dns_db_create(mctx, "rbt", name, dbtype, dns_rdataclass_in,
320			       0, NULL, db);
321	if (result != ISC_R_SUCCESS)
322		return (result);
323
324	result = dns_db_load(*db, testfile);
325	return (result);
326}
327