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