1/*	$NetBSD$	*/
2
3/*
4 * Copyright (C) 2004, 2005, 2007, 2009, 2011  Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1998-2001, 2003  Internet Software Consortium.
6 *
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19
20/* Id: t_rbt.c,v 1.35 2011/03/12 04:59:46 tbox Exp  */
21
22#include <config.h>
23
24#include <ctype.h>
25#include <stdlib.h>
26
27#include <isc/entropy.h>
28#include <isc/mem.h>
29#include <isc/util.h>
30#include <isc/hash.h>
31#include <isc/string.h>
32
33#include <dns/fixedname.h>
34#include <dns/rbt.h>
35#include <dns/result.h>
36
37#include <tests/t_api.h>
38
39#define		BUFLEN	1024
40#define		DNSNAMELEN 255
41
42char		*progname;
43char		*Tokens[T_MAXTOKS];
44
45static int
46t_dns_rbtnodechain_init(char *dbfile, char *findname,
47			char *firstname, char *firstorigin,
48			char *nextname, char *nextorigin,
49			char *prevname, char *prevorigin,
50			char *lastname, char *lastorigin);
51static char *
52fixedname_totext(dns_fixedname_t *name);
53
54static int
55fixedname_cmp(dns_fixedname_t *dns_name, char *txtname);
56
57static char *
58dnsname_totext(dns_name_t *name);
59
60static int
61t_namechk(isc_result_t dns_result, dns_fixedname_t *dns_name, char *exp_name,
62	  dns_fixedname_t *dns_origin, char *exp_origin,
63	  isc_result_t exp_result);
64
65/*
66 * Parts adapted from the original rbt_test.c.
67 */
68static int
69fixedname_cmp(dns_fixedname_t *dns_name, char *txtname) {
70	char	*name;
71
72	name = dnsname_totext(dns_fixedname_name(dns_name));
73	if (strcmp(txtname, "NULL") == 0) {
74		if ((name == NULL) || (*name == '\0'))
75			return(0);
76		return(1);
77	} else {
78		return(strcmp(name, txtname));
79	}
80}
81
82static char *
83dnsname_totext(dns_name_t *name) {
84	static char	buf[BUFLEN];
85	isc_buffer_t	target;
86
87	isc_buffer_init(&target, buf, BUFLEN);
88	dns_name_totext(name, ISC_FALSE, &target);
89	*((char *)(target.base) + target.used) = '\0';
90	return(target.base);
91}
92
93static char *
94fixedname_totext(dns_fixedname_t *name) {
95	static char	buf[BUFLEN];
96	isc_buffer_t	target;
97
98	memset(buf, 0, BUFLEN);
99	isc_buffer_init(&target, buf, BUFLEN);
100	dns_name_totext(dns_fixedname_name(name), ISC_FALSE, &target);
101	*((char *)(target.base) + target.used) = '\0';
102	return(target.base);
103}
104
105#ifdef	NEED_PRINT_DATA
106
107static isc_result_t
108print_data(void *data) {
109	isc_result_t	dns_result;
110	isc_buffer_t	target;
111	char		*buffer[DNSNAMELEN];
112
113	isc_buffer_init(&target, buffer, sizeof(buffer));
114
115	dns_result = dns_name_totext(data, ISC_FALSE, &target);
116	if (dns_result != ISC_R_SUCCESS) {
117		t_info("dns_name_totext failed %s\n",
118				dns_result_totext(dns_result));
119	}
120	return(dns_result);
121}
122
123#endif	/* NEED_PRINT_DATA */
124
125static int
126create_name(char *s, isc_mem_t *mctx, dns_name_t **dns_name) {
127	int		nfails;
128	int		length;
129	isc_result_t	result;
130	isc_buffer_t	source;
131	isc_buffer_t	target;
132	dns_name_t	*name;
133
134	nfails = 0;
135
136	if (s && *s) {
137
138		length = strlen(s);
139
140		isc_buffer_init(&source, s, length);
141		isc_buffer_add(&source, length);
142
143		/*
144		 * The buffer for the actual name will immediately follow the
145		 * name structure.
146		 */
147		name = isc_mem_get(mctx, sizeof(*name) + DNSNAMELEN);
148		if (name == NULL) {
149			t_info("isc_mem_get failed\n");
150			++nfails;
151		} else {
152
153			dns_name_init(name, NULL);
154			isc_buffer_init(&target, name + 1, DNSNAMELEN);
155
156			result = dns_name_fromtext(name, &source, dns_rootname,
157						   0, &target);
158
159			if (result != ISC_R_SUCCESS) {
160				++nfails;
161				t_info("dns_name_fromtext(%s) failed %s\n",
162				       s, dns_result_totext(result));
163				 isc_mem_put(mctx, name,
164					     sizeof(*name) + DNSNAMELEN);
165			} else
166				*dns_name = name;
167		}
168	} else {
169		++nfails;
170		t_info("create_name: empty name\n");
171	}
172
173	return(nfails);
174}
175
176static void
177delete_name(void *data, void *arg) {
178	isc_mem_put((isc_mem_t *)arg, data, sizeof(dns_name_t) + DNSNAMELEN);
179}
180
181
182/*
183 * Adapted from the original rbt_test.c.
184 */
185static int
186t1_add(char *name, dns_rbt_t *rbt, isc_mem_t *mctx, isc_result_t *dns_result) {
187	int		nprobs;
188	dns_name_t	*dns_name;
189
190	nprobs = 0;
191	if (name && dns_result) {
192		if (create_name(name, mctx, &dns_name) == 0) {
193			if (T_debug)
194				t_info("dns_rbt_addname succeeded\n");
195			*dns_result = dns_rbt_addname(rbt, dns_name, dns_name);
196			if (*dns_result != ISC_R_SUCCESS) {
197				delete_name(dns_name, mctx);
198				t_info("dns_rbt_addname failed %s\n",
199				       dns_result_totext(*dns_result));
200				++nprobs;
201			}
202		} else {
203			++nprobs;
204		}
205	} else {
206		++nprobs;
207	}
208	return(nprobs);
209}
210
211static int
212t1_delete(char *name, dns_rbt_t *rbt, isc_mem_t *mctx,
213	  isc_result_t *dns_result)
214{
215	int		nprobs;
216	dns_name_t	*dns_name;
217
218	nprobs = 0;
219	if (name && dns_result) {
220		if (create_name(name, mctx, &dns_name) == 0) {
221			*dns_result = dns_rbt_deletename(rbt, dns_name,
222							 ISC_FALSE);
223			delete_name(dns_name, mctx);
224		} else {
225			++nprobs;
226		}
227	} else {
228		++nprobs;
229	}
230	return(nprobs);
231}
232
233static int
234t1_search(char *name, dns_rbt_t *rbt, isc_mem_t *mctx,
235	  isc_result_t *dns_result)
236{
237	int		nprobs;
238	dns_name_t	*dns_searchname;
239	dns_name_t	*dns_foundname;
240	dns_fixedname_t	dns_fixedname;
241	void		*data;
242
243	nprobs = 0;
244	if (name && dns_result) {
245		if (create_name(name, mctx, &dns_searchname) == 0) {
246			dns_fixedname_init(&dns_fixedname);
247			dns_foundname = dns_fixedname_name(&dns_fixedname);
248			data = NULL;
249			*dns_result = dns_rbt_findname(rbt, dns_searchname, 0,
250						dns_foundname, &data);
251			delete_name(dns_searchname, mctx);
252		} else {
253			++nprobs;
254		}
255	} else {
256		++nprobs;
257	}
258	return(nprobs);
259}
260
261/*
262 * Initialize a database from filename.
263 */
264static int
265rbt_init(char *filename, dns_rbt_t **rbt, isc_mem_t *mctx) {
266	int		rval;
267	isc_result_t	dns_result;
268	char		*p;
269	FILE		*fp;
270
271	fp = fopen(filename, "r");
272	if (fp == NULL) {
273		t_info("No such file %s\n", filename);
274		return(1);
275	}
276
277	dns_result = dns_rbt_create(mctx, delete_name, mctx, rbt);
278	if (dns_result != ISC_R_SUCCESS) {
279		t_info("dns_rbt_create failed %s\n",
280				dns_result_totext(dns_result));
281		fclose(fp);
282		return(1);
283	}
284
285	while ((p = t_fgetbs(fp)) != NULL) {
286
287		/*
288		 * Skip any comment lines.
289		 */
290		if ((*p == '#') || (*p == '\0') || (*p == ' ')) {
291			(void)free(p);
292			continue;
293		}
294
295		if (T_debug)
296			t_info("adding name %s to the rbt\n", p);
297
298		rval = t1_add(p, *rbt, mctx, &dns_result);
299		if ((rval != 0) || (dns_result != ISC_R_SUCCESS)) {
300			t_info("add of %s failed\n", p);
301			dns_rbt_destroy(rbt);
302			fclose(fp);
303			return(1);
304		}
305		(void) free(p);
306	}
307	fclose(fp);
308	return(0);
309}
310
311static int
312test_rbt_gen(char *filename, char *command, char *testname,
313	     isc_result_t exp_result)
314{
315	int		rval;
316	int		result;
317	dns_rbt_t	*rbt;
318	isc_result_t	isc_result;
319	isc_result_t	dns_result;
320	isc_mem_t	*mctx;
321	isc_entropy_t	*ectx;
322	dns_name_t	*dns_name;
323
324	result = T_UNRESOLVED;
325
326	if (strcmp(command, "create") != 0)
327		t_info("testing using name %s\n", testname);
328
329	mctx = NULL;
330	ectx = NULL;
331
332	isc_result = isc_mem_create(0, 0, &mctx);
333	if (isc_result != ISC_R_SUCCESS) {
334		t_info("isc_mem_create: %s: exiting\n",
335		       dns_result_totext(isc_result));
336		return(T_UNRESOLVED);
337	}
338
339	isc_result = isc_entropy_create(mctx, &ectx);
340	if (isc_result != ISC_R_SUCCESS) {
341		t_info("isc_entropy_create: %s: exiting\n",
342		       dns_result_totext(isc_result));
343		isc_mem_destroy(&mctx);
344		return(T_UNRESOLVED);
345	}
346
347	isc_result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE);
348	if (isc_result != ISC_R_SUCCESS) {
349		t_info("isc_hash_create: %s: exiting\n",
350		       dns_result_totext(isc_result));
351		isc_entropy_detach(&ectx);
352		isc_mem_destroy(&mctx);
353		return(T_UNRESOLVED);
354	}
355
356	rbt = NULL;
357	if (rbt_init(filename, &rbt, mctx) != 0) {
358		if (strcmp(command, "create") == 0)
359			result = T_FAIL;
360		isc_hash_destroy();
361		isc_entropy_detach(&ectx);
362		isc_mem_destroy(&mctx);
363		return(result);
364	}
365
366	/*
367	 * Now try the database command.
368	 */
369	if (strcmp(command, "create") == 0) {
370		result = T_PASS;
371	} else if (strcmp(command, "add") == 0) {
372		if (create_name(testname, mctx, &dns_name) == 0) {
373			dns_result = dns_rbt_addname(rbt, dns_name, dns_name);
374
375			if (dns_result != ISC_R_SUCCESS)
376				delete_name(dns_name, mctx);
377
378			if (dns_result == exp_result) {
379				if (dns_result == ISC_R_SUCCESS) {
380					rval = t1_search(testname, rbt, mctx,
381							 &dns_result);
382					if (rval == 0) {
383					     if (dns_result == ISC_R_SUCCESS) {
384						     result = T_PASS;
385					     } else {
386						     result = T_FAIL;
387					     }
388					} else {
389						t_info("t1_search failed\n");
390						result = T_UNRESOLVED;
391					}
392				} else {
393					result = T_PASS;
394				}
395			} else {
396				t_info("dns_rbt_addname returned %s, "
397				       "expected %s\n",
398				       dns_result_totext(dns_result),
399				       dns_result_totext(exp_result));
400				result = T_FAIL;
401			}
402		} else {
403			t_info("create_name failed\n");
404			result = T_UNRESOLVED;
405		}
406	} else if ((strcmp(command, "delete") == 0) ||
407		   (strcmp(command, "nuke") == 0)) {
408		rval = t1_delete(testname, rbt, mctx, &dns_result);
409		if (rval == 0) {
410			if (dns_result == exp_result) {
411				rval = t1_search(testname, rbt, mctx,
412						 &dns_result);
413				if (rval == 0) {
414					if (dns_result == ISC_R_SUCCESS) {
415						t_info("dns_rbt_deletename "
416						       "didn't delete "
417						       "the name");
418						result = T_FAIL;
419					} else {
420						result = T_PASS;
421					}
422				}
423			} else {
424				t_info("delete returned %s, expected %s\n",
425					dns_result_totext(dns_result),
426					dns_result_totext(exp_result));
427				result = T_FAIL;
428			}
429		}
430	} else if (strcmp(command, "search") == 0) {
431		rval = t1_search(testname, rbt, mctx, &dns_result);
432		if (rval == 0) {
433			if (dns_result == exp_result) {
434				result = T_PASS;
435			} else {
436				t_info("find returned %s, expected %s\n",
437					dns_result_totext(dns_result),
438					dns_result_totext(exp_result));
439				result = T_FAIL;
440			}
441		}
442	}
443
444	dns_rbt_destroy(&rbt);
445	isc_hash_destroy();
446	isc_entropy_detach(&ectx);
447	isc_mem_destroy(&mctx);
448	return(result);
449}
450
451static int
452test_dns_rbt_x(const char *filename) {
453	FILE		*fp;
454	char		*p;
455	int		line;
456	int		cnt;
457	int		result;
458	int		nfails;
459	int		nprobs;
460
461	nfails = 0;
462	nprobs = 0;
463
464	fp = fopen(filename, "r");
465	if (fp != NULL) {
466		line = 0;
467		while ((p = t_fgetbs(fp)) != NULL) {
468
469			++line;
470
471			/*
472			 * Skip comment lines.
473			 */
474			if ((isspace((unsigned char)*p)) || (*p == '#')) {
475				(void)free(p);
476				continue;
477			}
478
479			/*
480			 * Name of db file, command, testname,
481			 * expected result.
482			 */
483			cnt = t_bustline(p, Tokens);
484			if (cnt == 4) {
485				result = test_rbt_gen(Tokens[0], Tokens[1],
486					     Tokens[2],
487					     t_dns_result_fromtext(Tokens[3]));
488				if (result != T_PASS)
489					++nfails;
490			} else {
491				t_info("bad format in %s at line %d\n",
492						filename, line);
493				++nprobs;
494			}
495
496			(void)free(p);
497		}
498		(void)fclose(fp);
499	} else {
500		t_info("Missing datafile %s\n", filename);
501		++nprobs;
502	}
503
504	result = T_UNRESOLVED;
505	if ((nfails == 0) && (nprobs == 0))
506		result = T_PASS;
507	else if (nfails)
508		result = T_FAIL;
509
510	return(result);
511}
512
513
514static const char *a1 =	"dns_rbt_create creates a rbt and returns "
515			"ISC_R_SUCCESS on success";
516
517static void
518t1() {
519	int	result;
520
521	t_assert("dns_rbt_create", 1, T_REQUIRED, "%s", a1);
522	result = test_dns_rbt_x("dns_rbt_create_1_data");
523	t_result(result);
524}
525
526static const char *a2 =	"dns_rbt_addname adds a name to a database and "
527			"returns ISC_R_SUCCESS on success";
528
529static void
530t2() {
531	int	result;
532
533	t_assert("dns_rbt_addname", 2, T_REQUIRED, "%s", a2);
534	result = test_dns_rbt_x("dns_rbt_addname_1_data");
535	t_result(result);
536}
537
538static const char *a3 =	"when name already exists, dns_rbt_addname() "
539			"returns ISC_R_EXISTS";
540
541static void
542t3() {
543	int	result;
544
545	t_assert("dns_rbt_addname", 3, T_REQUIRED, "%s", a3);
546	result = test_dns_rbt_x("dns_rbt_addname_2_data");
547	t_result(result);
548}
549
550static const char *a4 =	"when name exists, dns_rbt_deletename() returns "
551			"ISC_R_SUCCESS";
552
553static void
554t4() {
555	int	result;
556
557	t_assert("dns_rbt_deletename", 4, T_REQUIRED, "%s", a4);
558	result = test_dns_rbt_x("dns_rbt_deletename_1_data");
559	t_result(result);
560}
561
562static const char *a5 =	"when name does not exist, dns_rbt_deletename() "
563			"returns ISC_R_NOTFOUND";
564static void
565t5() {
566	int	result;
567
568	t_assert("dns_rbt_deletename", 5, T_REQUIRED, "%s", a5);
569	result = test_dns_rbt_x("dns_rbt_deletename_2_data");
570	t_result(result);
571}
572
573static const char *a6 =	"when name exists and exactly matches the "
574			"search name dns_rbt_findname() returns ISC_R_SUCCESS";
575
576static void
577t6() {
578	int	result;
579
580	t_assert("dns_rbt_findname", 6, T_REQUIRED, "%s", a6);
581	result = test_dns_rbt_x("dns_rbt_findname_1_data");
582	t_result(result);
583}
584
585static const char *a7 =	"when a name does not exist, "
586			"dns_rbt_findname returns ISC_R_NOTFOUND";
587
588static void
589t7() {
590	int	result;
591
592	t_assert("dns_rbt_findname", 7, T_REQUIRED, "%s", a7);
593	result = test_dns_rbt_x("dns_rbt_findname_2_data");
594	t_result(result);
595}
596
597static const char *a8 =	"when a superdomain is found with data matching name, "
598			"dns_rbt_findname returns DNS_R_PARTIALMATCH";
599
600static void
601t8() {
602	int	result;
603
604	t_assert("dns_rbt_findname", 8, T_REQUIRED, "%s", a8);
605	result = test_dns_rbt_x("dns_rbt_findname_3_data");
606	t_result(result);
607}
608
609
610static const char *a9 =	"a call to dns_rbtnodechain_init(chain, mctx) "
611			"initializes chain";
612
613static int
614t9_walkchain(dns_rbtnodechain_t *chain, dns_rbt_t *rbt) {
615	int		cnt;
616	int		order;
617	unsigned int	nlabels;
618	int		nprobs;
619	isc_result_t	dns_result;
620
621	dns_fixedname_t	name;
622	dns_fixedname_t	origin;
623	dns_fixedname_t	fullname1;
624	dns_fixedname_t	fullname2;
625
626	cnt = 0;
627	nprobs = 0;
628
629	do {
630
631		if (cnt == 0) {
632			dns_fixedname_init(&name);
633			dns_fixedname_init(&origin);
634			dns_result = dns_rbtnodechain_first(chain, rbt,
635						dns_fixedname_name(&name),
636						dns_fixedname_name(&origin));
637			if (dns_result != DNS_R_NEWORIGIN) {
638				t_info("dns_rbtnodechain_first returned %s, "
639				       "expecting DNS_R_NEWORIGIN\n",
640				       dns_result_totext(dns_result));
641				++nprobs;
642				break;
643			}
644			t_info("first name:\t<%s>\n", fixedname_totext(&name));
645			t_info("first origin:\t<%s>\n",
646			       fixedname_totext(&origin));
647		} else {
648			dns_fixedname_init(&fullname1);
649			dns_result = dns_name_concatenate(
650			       dns_fixedname_name(&name),
651			       dns_name_isabsolute(dns_fixedname_name(&name)) ?
652					    NULL : dns_fixedname_name(&origin),
653			       dns_fixedname_name(&fullname1), NULL);
654			if (dns_result != ISC_R_SUCCESS) {
655				t_info("dns_name_concatenate failed %s\n",
656				       dns_result_totext(dns_result));
657				++nprobs;
658				break;
659			}
660
661			/*
662			 * Expecting origin not to get touched if next
663			 * doesn't return NEWORIGIN.
664			 */
665			dns_fixedname_init(&name);
666			dns_result = dns_rbtnodechain_next(chain,
667						  dns_fixedname_name(&name),
668						  dns_fixedname_name(&origin));
669			if ((dns_result != ISC_R_SUCCESS) &&
670			    (dns_result != DNS_R_NEWORIGIN)) {
671				if (dns_result != ISC_R_NOMORE) {
672					t_info("dns_rbtnodechain_next "
673					       "failed %s\n",
674					       dns_result_totext(dns_result));
675					++nprobs;
676				}
677				break;
678			}
679
680			t_info("next name:\t<%s>\n", fixedname_totext(&name));
681			t_info("next origin:\t<%s>\n",
682			       fixedname_totext(&origin));
683
684			dns_fixedname_init(&fullname2);
685			dns_result = dns_name_concatenate(
686			       dns_fixedname_name(&name),
687			       dns_name_isabsolute(dns_fixedname_name(&name)) ?
688					    NULL : dns_fixedname_name(&origin),
689			       dns_fixedname_name(&fullname2), NULL);
690			if (dns_result != ISC_R_SUCCESS) {
691				t_info("dns_name_concatenate failed %s\n",
692				       dns_result_totext(dns_result));
693				++nprobs;
694				break;
695			}
696
697			t_info("comparing\t<%s>\n",
698			       fixedname_totext(&fullname1));
699			t_info("\twith\t<%s>\n", fixedname_totext(&fullname2));
700
701			(void)dns_name_fullcompare(
702						dns_fixedname_name(&fullname1),
703						dns_fixedname_name(&fullname2),
704						&order, &nlabels);
705
706			if (order >= 0) {
707			    t_info("unexpected order %s %s %s\n",
708			       dnsname_totext(dns_fixedname_name(&fullname1)),
709			       order == -1 ? "<" : (order == 0 ? "==" : ">"),
710			       dnsname_totext(dns_fixedname_name(&fullname2)));
711				++nprobs;
712			}
713		}
714
715		++cnt;
716	} while (1);
717
718	return (nprobs);
719}
720
721/*
722 * Test by exercising the first|last|next|prev funcs in useful ways.
723 */
724
725static int
726t_namechk(isc_result_t dns_result, dns_fixedname_t *dns_name, char *exp_name,
727	  dns_fixedname_t *dns_origin, char *exp_origin,
728	  isc_result_t exp_result)
729{
730	int	nfails;
731
732	nfails = 0;
733
734	if (fixedname_cmp(dns_name, exp_name)) {
735		t_info("\texpected name of %s, got %s\n",
736				exp_name, fixedname_totext(dns_name));
737		++nfails;
738	}
739	if (exp_origin != NULL) {
740		t_info("checking for DNS_R_NEWORIGIN\n");
741		if (dns_result == exp_result) {
742			if (fixedname_cmp(dns_origin, exp_origin)) {
743				t_info("\torigin %s, expected %s\n",
744				       fixedname_totext(dns_origin),
745				       exp_origin);
746				++nfails;
747			}
748		} else {
749			t_info("\tgot %s\n", dns_result_totext(dns_result));
750			++nfails;
751		}
752	}
753	return(nfails);
754}
755
756static int
757t_dns_rbtnodechain_init(char *dbfile, char *findname,
758			char *nextname, char *nextorigin,
759			char *prevname, char *prevorigin,
760			char *firstname, char *firstorigin,
761			char *lastname, char *lastorigin)
762{
763	int			result;
764	int			len;
765	int			nfails;
766	dns_rbt_t		*rbt;
767	dns_rbtnode_t		*node;
768	dns_rbtnodechain_t	chain;
769	isc_mem_t		*mctx;
770	isc_entropy_t		*ectx;
771	isc_result_t		isc_result;
772	isc_result_t		dns_result;
773	dns_fixedname_t		dns_findname;
774	dns_fixedname_t		dns_foundname;
775	dns_fixedname_t		dns_firstname;
776	dns_fixedname_t		dns_lastname;
777	dns_fixedname_t		dns_prevname;
778	dns_fixedname_t		dns_nextname;
779	dns_fixedname_t		dns_origin;
780	isc_buffer_t		isc_buffer;
781
782	result = T_UNRESOLVED;
783
784	nfails = 0;
785	mctx = NULL;
786	ectx = NULL;
787
788	isc_result = isc_mem_create(0, 0, &mctx);
789	if (isc_result != ISC_R_SUCCESS) {
790		t_info("isc_mem_create failed %s\n",
791		       isc_result_totext(isc_result));
792		return(result);
793	}
794
795	isc_result = isc_entropy_create(mctx, &ectx);
796	if (isc_result != ISC_R_SUCCESS) {
797		t_info("isc_entropy_create: %s: exiting\n",
798		       dns_result_totext(isc_result));
799		isc_mem_destroy(&mctx);
800		return(T_UNRESOLVED);
801	}
802
803	isc_result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE);
804	if (isc_result != ISC_R_SUCCESS) {
805		t_info("isc_hash_create: %s: exiting\n",
806		       dns_result_totext(isc_result));
807		isc_entropy_detach(&ectx);
808		isc_mem_destroy(&mctx);
809		return(T_UNRESOLVED);
810	}
811
812	dns_rbtnodechain_init(&chain, mctx);
813
814	rbt = NULL;
815	if (rbt_init(dbfile, &rbt, mctx)) {
816		t_info("rbt_init %s failed\n", dbfile);
817		isc_hash_destroy();
818		isc_entropy_detach(&ectx);
819		isc_mem_destroy(&mctx);
820		return(result);
821	}
822
823	len = strlen(findname);
824	isc_buffer_init(&isc_buffer, findname, len);
825	isc_buffer_add(&isc_buffer, len);
826
827	dns_fixedname_init(&dns_foundname);
828	dns_fixedname_init(&dns_findname);
829	dns_fixedname_init(&dns_firstname);
830	dns_fixedname_init(&dns_origin);
831	dns_fixedname_init(&dns_lastname);
832	dns_fixedname_init(&dns_prevname);
833	dns_fixedname_init(&dns_nextname);
834
835	dns_result = dns_name_fromtext(dns_fixedname_name(&dns_findname),
836					&isc_buffer, NULL, 0, NULL);
837
838	if (dns_result != ISC_R_SUCCESS) {
839		t_info("dns_name_fromtext failed %s\n",
840		       dns_result_totext(dns_result));
841		return(result);
842	}
843
844	/*
845	 * Set the starting node.
846	 */
847	node = NULL;
848	dns_result = dns_rbt_findnode(rbt, dns_fixedname_name(&dns_findname),
849				      dns_fixedname_name(&dns_foundname),
850				      &node, &chain, DNS_RBTFIND_EMPTYDATA,
851				      NULL, NULL);
852
853	if (dns_result != ISC_R_SUCCESS) {
854		t_info("dns_rbt_findnode failed %s\n",
855		       dns_result_totext(dns_result));
856		return(result);
857	}
858
859	/*
860	 * Check next.
861	 */
862	t_info("checking for next name of %s and new origin of %s\n",
863	       nextname, nextorigin);
864	dns_result = dns_rbtnodechain_next(&chain,
865					   dns_fixedname_name(&dns_nextname),
866					   dns_fixedname_name(&dns_origin));
867
868	if ((dns_result != ISC_R_SUCCESS) &&
869	    (dns_result != DNS_R_NEWORIGIN)) {
870		t_info("dns_rbtnodechain_next unexpectedly returned %s\n",
871		       dns_result_totext(dns_result));
872	}
873
874	nfails += t_namechk(dns_result, &dns_nextname, nextname, &dns_origin,
875			    nextorigin, DNS_R_NEWORIGIN);
876
877	/*
878	 * Set the starting node again.
879	 */
880	node = NULL;
881	dns_fixedname_init(&dns_foundname);
882	dns_result = dns_rbt_findnode(rbt, dns_fixedname_name(&dns_findname),
883				      dns_fixedname_name(&dns_foundname),
884				      &node, &chain, DNS_RBTFIND_EMPTYDATA,
885				      NULL, NULL);
886
887	if (dns_result != ISC_R_SUCCESS) {
888		t_info("\tdns_rbt_findnode failed %s\n",
889		       dns_result_totext(dns_result));
890		return(result);
891	}
892
893	/*
894	 * Check previous.
895	 */
896	t_info("checking for previous name of %s and new origin of %s\n",
897	       prevname, prevorigin);
898	dns_fixedname_init(&dns_origin);
899	dns_result = dns_rbtnodechain_prev(&chain,
900					   dns_fixedname_name(&dns_prevname),
901					   dns_fixedname_name(&dns_origin));
902
903	if ((dns_result != ISC_R_SUCCESS) &&
904	    (dns_result != DNS_R_NEWORIGIN)) {
905		t_info("dns_rbtnodechain_prev unexpectedly returned %s\n",
906		       dns_result_totext(dns_result));
907	}
908	nfails += t_namechk(dns_result, &dns_prevname, prevname, &dns_origin,
909			    prevorigin, DNS_R_NEWORIGIN);
910
911	/*
912	 * Check first.
913	 */
914	t_info("checking for first name of %s and new origin of %s\n",
915	       firstname, firstorigin);
916	dns_result = dns_rbtnodechain_first(&chain, rbt,
917					    dns_fixedname_name(&dns_firstname),
918					    dns_fixedname_name(&dns_origin));
919
920	if (dns_result != DNS_R_NEWORIGIN) {
921		t_info("dns_rbtnodechain_first unexpectedly returned %s\n",
922		       dns_result_totext(dns_result));
923	}
924	nfails += t_namechk(dns_result, &dns_firstname, firstname,
925			    &dns_origin, firstorigin, DNS_R_NEWORIGIN);
926
927	/*
928	 * Check last.
929	 */
930	t_info("checking for last name of %s\n", lastname);
931	dns_result = dns_rbtnodechain_last(&chain, rbt,
932					   dns_fixedname_name(&dns_lastname),
933					   dns_fixedname_name(&dns_origin));
934
935	if (dns_result != DNS_R_NEWORIGIN) {
936		t_info("dns_rbtnodechain_last unexpectedly returned %s\n",
937		       dns_result_totext(dns_result));
938	}
939	nfails += t_namechk(dns_result, &dns_lastname, lastname, &dns_origin,
940			    lastorigin, DNS_R_NEWORIGIN);
941
942	/*
943	 * Check node ordering.
944	 */
945	t_info("checking node ordering\n");
946	nfails += t9_walkchain(&chain, rbt);
947
948	if (nfails)
949		result = T_FAIL;
950	else
951		result = T_PASS;
952
953	dns_rbtnodechain_invalidate(&chain);
954	dns_rbt_destroy(&rbt);
955
956	isc_hash_destroy();
957	isc_entropy_detach(&ectx);
958	isc_mem_destroy(&mctx);
959
960	return(result);
961}
962
963static int
964test_dns_rbtnodechain_init(const char *filename) {
965	FILE		*fp;
966	char		*p;
967	int		line;
968	int		cnt;
969	int		result;
970	int		nfails;
971	int		nprobs;
972
973	nfails = 0;
974	nprobs = 0;
975
976	fp = fopen(filename, "r");
977	if (fp != NULL) {
978		line = 0;
979		while ((p = t_fgetbs(fp)) != NULL) {
980
981			++line;
982
983			/*
984			 * Skip comment lines.
985			 */
986			if ((isspace((unsigned char)*p)) || (*p == '#')) {
987				(void)free(p);
988				continue;
989			}
990
991			cnt = t_bustline(p, Tokens);
992			if (cnt == 10) {
993				result = t_dns_rbtnodechain_init(
994						Tokens[0],  /* dbfile */
995						Tokens[1],  /* startname */
996						Tokens[2],  /* nextname */
997						Tokens[3],  /* nextorigin */
998						Tokens[4],  /* prevname */
999						Tokens[5],  /* prevorigin */
1000						Tokens[6],  /* firstname */
1001						Tokens[7],  /* firstorigin */
1002						Tokens[8],  /* lastname */
1003						Tokens[9]); /* lastorigin */
1004				if (result != T_PASS) {
1005					if (result == T_FAIL)
1006						++nfails;
1007					else
1008						++nprobs;
1009				}
1010			} else {
1011				t_info("bad format in %s at line %d\n",
1012						filename, line);
1013				++nprobs;
1014			}
1015
1016			(void)free(p);
1017		}
1018		(void)fclose(fp);
1019	} else {
1020		t_info("Missing datafile %s\n", filename);
1021		++nprobs;
1022	}
1023
1024	result = T_UNRESOLVED;
1025
1026	if ((nfails == 0) && (nprobs == 0))
1027		result = T_PASS;
1028	else if (nfails)
1029		result = T_FAIL;
1030
1031	return(result);
1032}
1033
1034static void
1035t9() {
1036	int	result;
1037
1038	t_assert("dns_rbtnodechain_init", 9, T_REQUIRED, "%s", a9);
1039	result = test_dns_rbtnodechain_init("dns_rbtnodechain_init_data");
1040	t_result(result);
1041}
1042
1043static int
1044t_dns_rbtnodechain_first(char *dbfile, char *expected_firstname,
1045				char *expected_firstorigin,
1046				char *expected_nextname,
1047				char *expected_nextorigin)
1048{
1049	int			result;
1050	int			nfails;
1051	dns_rbt_t		*rbt;
1052	dns_rbtnodechain_t	chain;
1053	isc_mem_t		*mctx;
1054	isc_entropy_t		*ectx;
1055	isc_result_t		isc_result;
1056	isc_result_t		dns_result;
1057	dns_fixedname_t		dns_name;
1058	dns_fixedname_t		dns_origin;
1059	isc_result_t		expected_result;
1060
1061	result = T_UNRESOLVED;
1062
1063	nfails = 0;
1064	mctx = NULL;
1065	ectx = NULL;
1066
1067	dns_fixedname_init(&dns_name);
1068	dns_fixedname_init(&dns_origin);
1069
1070	isc_result = isc_mem_create(0, 0, &mctx);
1071	if (isc_result != ISC_R_SUCCESS) {
1072		t_info("isc_mem_create failed %s\n",
1073		       isc_result_totext(isc_result));
1074		return(result);
1075	}
1076
1077	isc_result = isc_entropy_create(mctx, &ectx);
1078	if (isc_result != ISC_R_SUCCESS) {
1079		t_info("isc_entropy_create: %s: exiting\n",
1080		       dns_result_totext(isc_result));
1081		isc_mem_destroy(&mctx);
1082		return(T_UNRESOLVED);
1083	}
1084
1085	isc_result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE);
1086	if (isc_result != ISC_R_SUCCESS) {
1087		t_info("isc_hash_create: %s: exiting\n",
1088		       dns_result_totext(isc_result));
1089		isc_entropy_detach(&ectx);
1090		isc_mem_destroy(&mctx);
1091		return(T_UNRESOLVED);
1092	}
1093
1094	dns_rbtnodechain_init(&chain, mctx);
1095
1096	rbt = NULL;
1097	if (rbt_init(dbfile, &rbt, mctx)) {
1098		t_info("rbt_init %s failed\n", dbfile);
1099		isc_hash_destroy();
1100		isc_entropy_detach(&ectx);
1101		isc_mem_destroy(&mctx);
1102		return(result);
1103	}
1104
1105	t_info("testing for first name of %s, origin of %s\n",
1106	       expected_firstname, expected_firstorigin);
1107
1108	dns_result = dns_rbtnodechain_first(&chain, rbt,
1109					    dns_fixedname_name(&dns_name),
1110					    dns_fixedname_name(&dns_origin));
1111
1112	if (dns_result != DNS_R_NEWORIGIN)
1113		t_info("dns_rbtnodechain_first unexpectedly returned %s\n",
1114		       dns_result_totext(dns_result));
1115
1116	nfails += t_namechk(dns_result, &dns_name, expected_firstname,
1117			    &dns_origin, expected_firstorigin, DNS_R_NEWORIGIN);
1118
1119	dns_fixedname_init(&dns_name);
1120	dns_result = dns_rbtnodechain_next(&chain,
1121			dns_fixedname_name(&dns_name),
1122			dns_fixedname_name(&dns_origin));
1123
1124	t_info("testing for next name of %s, origin of %s\n",
1125			expected_nextname, expected_nextorigin);
1126
1127	if ((dns_result != ISC_R_SUCCESS) && (dns_result != DNS_R_NEWORIGIN))
1128		t_info("dns_rbtnodechain_next unexpectedly returned %s\n",
1129		       dns_result_totext(dns_result));
1130
1131	if (strcasecmp(expected_firstorigin, expected_nextorigin) == 0)
1132		expected_result = ISC_R_SUCCESS;
1133	else
1134		expected_result = DNS_R_NEWORIGIN;
1135	nfails += t_namechk(dns_result, &dns_name, expected_nextname,
1136			    &dns_origin, expected_nextorigin, expected_result);
1137
1138	if (nfails)
1139		result = T_FAIL;
1140	else
1141		result = T_PASS;
1142
1143	dns_rbtnodechain_invalidate(&chain);
1144
1145	dns_rbt_destroy(&rbt);
1146	isc_hash_destroy();
1147	isc_entropy_detach(&ectx);
1148	isc_mem_destroy(&mctx);
1149	return(result);
1150}
1151
1152static int
1153test_dns_rbtnodechain_first(const char *filename) {
1154	FILE		*fp;
1155	char		*p;
1156	int		line;
1157	int		cnt;
1158	int		result;
1159	int		nfails;
1160	int		nprobs;
1161
1162	nfails = 0;
1163	nprobs = 0;
1164
1165	fp = fopen(filename, "r");
1166	if (fp != NULL) {
1167		line = 0;
1168		while ((p = t_fgetbs(fp)) != NULL) {
1169
1170			++line;
1171
1172			/*
1173			 * Skip comment lines.
1174			 */
1175			if ((isspace((unsigned char)*p)) || (*p == '#')) {
1176				(void)free(p);
1177				continue;
1178			}
1179
1180			cnt = t_bustline(p, Tokens);
1181			if (cnt == 5) {
1182				result = t_dns_rbtnodechain_first(
1183						Tokens[0],  /* dbfile */
1184						Tokens[1],  /* firstname */
1185						Tokens[2],  /* firstorigin */
1186						Tokens[3],  /* nextname */
1187						Tokens[4]); /* nextorigin */
1188				if (result != T_PASS) {
1189					if (result == T_FAIL)
1190						++nfails;
1191					else
1192						++nprobs;
1193				}
1194			} else {
1195				t_info("bad format in %s at line %d\n",
1196						filename, line);
1197				++nprobs;
1198			}
1199
1200			(void)free(p);
1201		}
1202		(void)fclose(fp);
1203	} else {
1204		t_info("Missing datafile %s\n", filename);
1205		++nprobs;
1206	}
1207
1208	result = T_UNRESOLVED;
1209
1210	if ((nfails == 0) && (nprobs == 0))
1211		result = T_PASS;
1212	else if (nfails)
1213		result = T_FAIL;
1214
1215	return(result);
1216}
1217
1218static const char *a10 = "a call to "
1219			"dns_rbtnodechain_first(chain, rbt, name, origin) "
1220			"sets name to point to the root of the tree, "
1221			"origin to point to the origin, "
1222			"and returns DNS_R_NEWORIGIN";
1223
1224static void
1225t10() {
1226	int	result;
1227
1228	t_assert("dns_rbtnodechain_first", 10, T_REQUIRED, "%s", a10);
1229	result = test_dns_rbtnodechain_first("dns_rbtnodechain_first_data");
1230	t_result(result);
1231}
1232
1233static int
1234t_dns_rbtnodechain_last(char *dbfile, char *expected_lastname,
1235			char *expected_lastorigin,
1236			char *expected_prevname,
1237			char *expected_prevorigin)
1238{
1239
1240	int			result;
1241	int			nfails;
1242	dns_rbt_t		*rbt;
1243	dns_rbtnodechain_t	chain;
1244	isc_mem_t		*mctx;
1245	isc_entropy_t		*ectx;
1246	isc_result_t		isc_result;
1247	isc_result_t		dns_result;
1248	dns_fixedname_t		dns_name;
1249	dns_fixedname_t		dns_origin;
1250	isc_result_t		expected_result;
1251
1252	result = T_UNRESOLVED;
1253
1254	nfails = 0;
1255	mctx = NULL;
1256	ectx = NULL;
1257
1258	dns_fixedname_init(&dns_name);
1259	dns_fixedname_init(&dns_origin);
1260
1261	isc_result = isc_mem_create(0, 0, &mctx);
1262	if (isc_result != ISC_R_SUCCESS) {
1263		t_info("isc_mem_create failed %s\n",
1264		       isc_result_totext(isc_result));
1265		return(result);
1266	}
1267
1268	isc_result = isc_entropy_create(mctx, &ectx);
1269	if (isc_result != ISC_R_SUCCESS) {
1270		t_info("isc_entropy_create: %s: exiting\n",
1271		       dns_result_totext(isc_result));
1272		isc_mem_destroy(&mctx);
1273		return(T_UNRESOLVED);
1274	}
1275
1276	isc_result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE);
1277	if (isc_result != ISC_R_SUCCESS) {
1278		t_info("isc_hash_create: %s: exiting\n",
1279		       dns_result_totext(isc_result));
1280		isc_entropy_detach(&ectx);
1281		isc_mem_destroy(&mctx);
1282		return(T_UNRESOLVED);
1283	}
1284
1285	dns_rbtnodechain_init(&chain, mctx);
1286
1287	rbt = NULL;
1288	if (rbt_init(dbfile, &rbt, mctx)) {
1289		t_info("rbt_init %s failed\n", dbfile);
1290		isc_hash_destroy();
1291		isc_entropy_detach(&ectx);
1292		isc_mem_destroy(&mctx);
1293		return(result);
1294	}
1295
1296	t_info("testing for last name of %s, origin of %s\n",
1297	       expected_lastname, expected_lastorigin);
1298
1299	dns_result = dns_rbtnodechain_last(&chain, rbt,
1300					   dns_fixedname_name(&dns_name),
1301					   dns_fixedname_name(&dns_origin));
1302
1303	if (dns_result != DNS_R_NEWORIGIN) {
1304		t_info("dns_rbtnodechain_last unexpectedly returned %s\n",
1305		       dns_result_totext(dns_result));
1306	}
1307	nfails += t_namechk(dns_result, &dns_name, expected_lastname,
1308			    &dns_origin, expected_lastorigin, DNS_R_NEWORIGIN);
1309
1310	t_info("testing for previous name of %s, origin of %s\n",
1311	       expected_prevname, expected_prevorigin);
1312
1313	dns_fixedname_init(&dns_name);
1314	dns_result = dns_rbtnodechain_prev(&chain,
1315					   dns_fixedname_name(&dns_name),
1316					   dns_fixedname_name(&dns_origin));
1317
1318	if ((dns_result != ISC_R_SUCCESS) &&
1319	    (dns_result != DNS_R_NEWORIGIN)) {
1320		t_info("dns_rbtnodechain_prev unexpectedly returned %s\n",
1321		       dns_result_totext(dns_result));
1322	}
1323	if (strcasecmp(expected_lastorigin, expected_prevorigin) == 0)
1324		expected_result = ISC_R_SUCCESS;
1325	else
1326		expected_result = DNS_R_NEWORIGIN;
1327	nfails += t_namechk(dns_result, &dns_name, expected_prevname,
1328			    &dns_origin, expected_prevorigin, expected_result);
1329
1330	if (nfails)
1331		result = T_FAIL;
1332	else
1333		result = T_PASS;
1334
1335	dns_rbtnodechain_invalidate(&chain);
1336	dns_rbt_destroy(&rbt);
1337
1338	isc_hash_destroy();
1339	isc_entropy_detach(&ectx);
1340	isc_mem_destroy(&mctx);
1341
1342	return(result);
1343}
1344
1345static int
1346test_dns_rbtnodechain_last(const char *filename) {
1347	FILE		*fp;
1348	char		*p;
1349	int		line;
1350	int		cnt;
1351	int		result;
1352	int		nfails;
1353	int		nprobs;
1354
1355	nfails = 0;
1356	nprobs = 0;
1357
1358	fp = fopen(filename, "r");
1359	if (fp != NULL) {
1360		line = 0;
1361		while ((p = t_fgetbs(fp)) != NULL) {
1362
1363			++line;
1364
1365			/*
1366			 * Skip comment lines.
1367			 */
1368			if ((isspace((unsigned char)*p)) || (*p == '#')) {
1369				(void)free(p);
1370				continue;
1371			}
1372
1373			cnt = t_bustline(p, Tokens);
1374			if (cnt == 5) {
1375				result = t_dns_rbtnodechain_last(
1376						Tokens[0],     /* dbfile */
1377						Tokens[1],     /* lastname */
1378						Tokens[2],     /* lastorigin */
1379						Tokens[3],     /* prevname */
1380						Tokens[4]);    /* prevorigin */
1381				if (result != T_PASS) {
1382					if (result == T_FAIL)
1383						++nfails;
1384					else
1385						++nprobs;
1386				}
1387			} else {
1388				t_info("bad format in %s at line %d\n",
1389				       filename, line);
1390				++nprobs;
1391			}
1392
1393			(void)free(p);
1394		}
1395		(void)fclose(fp);
1396	} else {
1397		t_info("Missing datafile %s\n", filename);
1398		++nprobs;
1399	}
1400
1401	result = T_UNRESOLVED;
1402
1403	if ((nfails == 0) && (nprobs == 0))
1404		result = T_PASS;
1405	else if (nfails)
1406		result = T_FAIL;
1407
1408	return(result);
1409}
1410
1411static const char *a11 = "a call to "
1412			"dns_rbtnodechain_last(chain, rbt, name, origin) "
1413			"sets name to point to the last node of the megatree, "
1414			"origin to the name of the level above it, "
1415			"and returns DNS_R_NEWORIGIN";
1416
1417static void
1418t11() {
1419	int	result;
1420
1421	t_assert("dns_rbtnodechain_last", 11, T_REQUIRED, "%s", a11);
1422	result = test_dns_rbtnodechain_last("dns_rbtnodechain_last_data");
1423	t_result(result);
1424}
1425
1426static int
1427t_dns_rbtnodechain_next(char *dbfile, char *findname,
1428			char *nextname, char *nextorigin)
1429{
1430
1431	int			result;
1432	int			len;
1433	int			nfails;
1434	dns_rbt_t		*rbt;
1435	dns_rbtnode_t		*node;
1436	dns_rbtnodechain_t	chain;
1437	isc_mem_t		*mctx;
1438	isc_entropy_t		*ectx;
1439	isc_result_t		isc_result;
1440	isc_result_t		dns_result;
1441	dns_fixedname_t		dns_findname;
1442	dns_fixedname_t		dns_foundname;
1443	dns_fixedname_t		dns_nextname;
1444	dns_fixedname_t		dns_origin;
1445	isc_buffer_t		isc_buffer;
1446
1447	result = T_UNRESOLVED;
1448
1449	nfails = 0;
1450	mctx = NULL;
1451	ectx = NULL;
1452
1453	isc_result = isc_mem_create(0, 0, &mctx);
1454	if (isc_result != ISC_R_SUCCESS) {
1455		t_info("isc_mem_create failed %s\n",
1456		       isc_result_totext(isc_result));
1457		return(result);
1458	}
1459
1460	isc_result = isc_entropy_create(mctx, &ectx);
1461	if (isc_result != ISC_R_SUCCESS) {
1462		t_info("isc_entropy_create: %s: exiting\n",
1463		       dns_result_totext(isc_result));
1464		isc_mem_destroy(&mctx);
1465		return(T_UNRESOLVED);
1466	}
1467
1468	isc_result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE);
1469	if (isc_result != ISC_R_SUCCESS) {
1470		t_info("isc_hash_create: %s: exiting\n",
1471		       dns_result_totext(isc_result));
1472		isc_entropy_detach(&ectx);
1473		isc_mem_destroy(&mctx);
1474		return(T_UNRESOLVED);
1475	}
1476
1477	dns_rbtnodechain_init(&chain, mctx);
1478
1479	rbt = NULL;
1480	if (rbt_init(dbfile, &rbt, mctx)) {
1481		t_info("rbt_init %s failed\n", dbfile);
1482		isc_hash_destroy();
1483		isc_entropy_detach(&ectx);
1484		isc_mem_destroy(&mctx);
1485		return(result);
1486	}
1487
1488	len = strlen(findname);
1489	isc_buffer_init(&isc_buffer, findname, len);
1490	isc_buffer_add(&isc_buffer, len);
1491
1492	dns_fixedname_init(&dns_foundname);
1493	dns_fixedname_init(&dns_findname);
1494	dns_fixedname_init(&dns_nextname);
1495	dns_fixedname_init(&dns_origin);
1496
1497	dns_result = dns_name_fromtext(dns_fixedname_name(&dns_findname),
1498				       &isc_buffer, NULL, 0, NULL);
1499
1500	if (dns_result != ISC_R_SUCCESS) {
1501		t_info("dns_name_fromtext failed %s\n",
1502		       dns_result_totext(dns_result));
1503		return(result);
1504	}
1505
1506	/*
1507	 * Set the starting node.
1508	 */
1509	node = NULL;
1510	dns_result = dns_rbt_findnode(rbt, dns_fixedname_name(&dns_findname),
1511				      dns_fixedname_name(&dns_foundname),
1512				      &node, &chain, DNS_RBTFIND_EMPTYDATA,
1513				      NULL, NULL);
1514
1515	if (dns_result != ISC_R_SUCCESS) {
1516		t_info("dns_rbt_findnode failed %s\n",
1517		       dns_result_totext(dns_result));
1518		return(result);
1519	}
1520
1521	/*
1522	 * Check next.
1523	 */
1524	t_info("checking for next name of %s and new origin of %s\n",
1525	       nextname, nextorigin);
1526	dns_result = dns_rbtnodechain_next(&chain,
1527					   dns_fixedname_name(&dns_nextname),
1528					   dns_fixedname_name(&dns_origin));
1529
1530	if ((dns_result != ISC_R_SUCCESS) && (dns_result != DNS_R_NEWORIGIN)) {
1531		t_info("dns_rbtnodechain_next unexpectedly returned %s\n",
1532		       dns_result_totext(dns_result));
1533	}
1534
1535	nfails += t_namechk(dns_result, &dns_nextname, nextname, &dns_origin,
1536			    nextorigin, DNS_R_NEWORIGIN);
1537
1538	if (nfails)
1539		result = T_FAIL;
1540	else
1541		result = T_PASS;
1542
1543	dns_rbtnodechain_invalidate(&chain);
1544	dns_rbt_destroy(&rbt);
1545
1546	isc_hash_destroy();
1547	isc_entropy_detach(&ectx);
1548	isc_mem_destroy(&mctx);
1549
1550	return(result);
1551}
1552
1553static int
1554test_dns_rbtnodechain_next(const char *filename) {
1555	FILE		*fp;
1556	char		*p;
1557	int		line;
1558	int		cnt;
1559	int		result;
1560	int		nfails;
1561	int		nprobs;
1562
1563	nfails = 0;
1564	nprobs = 0;
1565
1566	fp = fopen(filename, "r");
1567	if (fp != NULL) {
1568		line = 0;
1569		while ((p = t_fgetbs(fp)) != NULL) {
1570
1571			++line;
1572
1573			/*
1574			 * Skip comment lines.
1575			 */
1576			if ((isspace((unsigned char)*p)) || (*p == '#')) {
1577				(void)free(p);
1578				continue;
1579			}
1580
1581			cnt = t_bustline(p, Tokens);
1582			if (cnt == 4) {
1583				result = t_dns_rbtnodechain_next(
1584						Tokens[0],     /* dbfile */
1585						Tokens[1],     /* findname */
1586						Tokens[2],     /* nextname */
1587						Tokens[3]);    /* nextorigin */
1588				if (result != T_PASS) {
1589					if (result == T_FAIL)
1590						++nfails;
1591					else
1592						++nprobs;
1593				}
1594			} else {
1595				t_info("bad format in %s at line %d\n",
1596				       filename, line);
1597				++nprobs;
1598			}
1599
1600			(void)free(p);
1601		}
1602		(void)fclose(fp);
1603	} else {
1604		t_info("Missing datafile %s\n", filename);
1605		++nprobs;
1606	}
1607
1608	result = T_UNRESOLVED;
1609
1610	if ((nfails == 0) && (nprobs == 0))
1611		result = T_PASS;
1612	else if (nfails)
1613		result = T_FAIL;
1614
1615	return(result);
1616}
1617
1618static const char *a12 = "a call to "
1619			"dns_rbtnodechain_next(chain, name, origin) "
1620			"sets name to point to the next node of the tree "
1621			"and returns ISC_R_SUCCESS or "
1622			"DNS_R_NEWORIGIN on success";
1623
1624
1625static void
1626t12() {
1627	int	result;
1628
1629	t_assert("dns_rbtnodechain_next", 12, T_REQUIRED, "%s", a12);
1630	result = test_dns_rbtnodechain_next("dns_rbtnodechain_next_data");
1631	t_result(result);
1632}
1633
1634static int
1635t_dns_rbtnodechain_prev(char *dbfile, char *findname, char *prevname,
1636			char *prevorigin)
1637{
1638	int			result;
1639	int			len;
1640	int			nfails;
1641	dns_rbt_t		*rbt;
1642	dns_rbtnode_t		*node;
1643	dns_rbtnodechain_t	chain;
1644	isc_mem_t		*mctx;
1645	isc_entropy_t		*ectx = NULL;
1646	isc_result_t		isc_result;
1647	isc_result_t		dns_result;
1648	dns_fixedname_t		dns_findname;
1649	dns_fixedname_t		dns_foundname;
1650	dns_fixedname_t		dns_prevname;
1651	dns_fixedname_t		dns_origin;
1652	isc_buffer_t		isc_buffer;
1653
1654	result = T_UNRESOLVED;
1655
1656	nfails = 0;
1657	mctx = NULL;
1658	ectx = NULL;
1659
1660	isc_result = isc_mem_create(0, 0, &mctx);
1661	if (isc_result != ISC_R_SUCCESS) {
1662		t_info("isc_mem_create failed %s\n",
1663		       isc_result_totext(isc_result));
1664		return(result);
1665	}
1666
1667	isc_result = isc_entropy_create(mctx, &ectx);
1668	if (isc_result != ISC_R_SUCCESS) {
1669		t_info("isc_entropy_create: %s: exiting\n",
1670		       dns_result_totext(isc_result));
1671		isc_mem_destroy(&mctx);
1672		return(T_UNRESOLVED);
1673	}
1674
1675	isc_result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE);
1676	if (isc_result != ISC_R_SUCCESS) {
1677		t_info("isc_hash_create: %s: exiting\n",
1678		       dns_result_totext(isc_result));
1679		isc_entropy_detach(&ectx);
1680		isc_mem_destroy(&mctx);
1681		return(T_UNRESOLVED);
1682	}
1683
1684	dns_rbtnodechain_init(&chain, mctx);
1685
1686	rbt = NULL;
1687	if (rbt_init(dbfile, &rbt, mctx)) {
1688		t_info("rbt_init %s failed\n", dbfile);
1689		isc_hash_destroy();
1690		isc_entropy_detach(&ectx);
1691		isc_mem_destroy(&mctx);
1692		return(result);
1693	}
1694
1695	len = strlen(findname);
1696	isc_buffer_init(&isc_buffer, findname, len);
1697	isc_buffer_add(&isc_buffer, len);
1698
1699	dns_fixedname_init(&dns_foundname);
1700	dns_fixedname_init(&dns_findname);
1701	dns_fixedname_init(&dns_prevname);
1702	dns_fixedname_init(&dns_origin);
1703
1704	dns_result = dns_name_fromtext(dns_fixedname_name(&dns_findname),
1705				       &isc_buffer, NULL, 0, NULL);
1706
1707	if (dns_result != ISC_R_SUCCESS) {
1708		t_info("dns_name_fromtext failed %s\n",
1709		       dns_result_totext(dns_result));
1710		return(result);
1711	}
1712
1713	/*
1714	 * Set the starting node.
1715	 */
1716	node = NULL;
1717	dns_result = dns_rbt_findnode(rbt, dns_fixedname_name(&dns_findname),
1718				      dns_fixedname_name(&dns_foundname),
1719				      &node, &chain, DNS_RBTFIND_EMPTYDATA,
1720				      NULL, NULL);
1721
1722	if (dns_result != ISC_R_SUCCESS) {
1723		t_info("dns_rbt_findnode failed %s\n",
1724		       dns_result_totext(dns_result));
1725		return(result);
1726	}
1727
1728	/*
1729	 * Check next.
1730	 */
1731	t_info("checking for next name of %s and new origin of %s\n",
1732	       prevname, prevorigin);
1733	dns_result = dns_rbtnodechain_prev(&chain,
1734					   dns_fixedname_name(&dns_prevname),
1735					   dns_fixedname_name(&dns_origin));
1736
1737	if ((dns_result != ISC_R_SUCCESS) && (dns_result != DNS_R_NEWORIGIN)) {
1738		t_info("dns_rbtnodechain_prev unexpectedly returned %s\n",
1739		       dns_result_totext(dns_result));
1740	}
1741
1742	nfails += t_namechk(dns_result, &dns_prevname, prevname, &dns_origin,
1743			    prevorigin, DNS_R_NEWORIGIN);
1744
1745	if (nfails)
1746		result = T_FAIL;
1747	else
1748		result = T_PASS;
1749
1750	dns_rbtnodechain_invalidate(&chain);
1751	dns_rbt_destroy(&rbt);
1752
1753	isc_hash_destroy();
1754	isc_entropy_detach(&ectx);
1755	isc_mem_destroy(&mctx);
1756
1757	return(result);
1758}
1759
1760static int
1761test_dns_rbtnodechain_prev(const char *filename) {
1762	FILE		*fp;
1763	char		*p;
1764	int		line;
1765	int		cnt;
1766	int		result;
1767	int		nfails;
1768	int		nprobs;
1769
1770	nfails = 0;
1771	nprobs = 0;
1772
1773	fp = fopen(filename, "r");
1774	if (fp != NULL) {
1775		line = 0;
1776		while ((p = t_fgetbs(fp)) != NULL) {
1777
1778			++line;
1779
1780			/*
1781			 * Skip comment lines.
1782			 */
1783			if ((isspace((unsigned char)*p)) || (*p == '#')) {
1784				(void)free(p);
1785				continue;
1786			}
1787
1788			cnt = t_bustline(p, Tokens);
1789			if (cnt == 4) {
1790				result = t_dns_rbtnodechain_prev(
1791						Tokens[0],     /* dbfile */
1792						Tokens[1],     /* findname */
1793						Tokens[2],     /* prevname */
1794						Tokens[3]);    /* prevorigin */
1795				if (result != T_PASS) {
1796					if (result == T_FAIL)
1797						++nfails;
1798					else
1799						++nprobs;
1800				}
1801			} else {
1802				t_info("bad format in %s at line %d\n",
1803						filename, line);
1804				++nprobs;
1805			}
1806
1807			(void)free(p);
1808		}
1809		(void)fclose(fp);
1810	} else {
1811		t_info("Missing datafile %s\n", filename);
1812		++nprobs;
1813	}
1814
1815	result = T_UNRESOLVED;
1816
1817	if ((nfails == 0) && (nprobs == 0))
1818		result = T_PASS;
1819	else if (nfails)
1820		result = T_FAIL;
1821
1822	return(result);
1823}
1824
1825static const char *a13 = "a call to "
1826			"dns_rbtnodechain_prev(chain, name, origin) "
1827			"sets name to point to the previous node of the tree "
1828			"and returns ISC_R_SUCCESS or "
1829			"DNS_R_NEWORIGIN on success";
1830
1831static void
1832t13() {
1833	int	result;
1834
1835	t_assert("dns_rbtnodechain_prev", 13, T_REQUIRED, "%s", a13);
1836	result = test_dns_rbtnodechain_prev("dns_rbtnodechain_prev_data");
1837	t_result(result);
1838}
1839
1840
1841
1842testspec_t	T_testlist[] = {
1843	{	t1,	"dns_rbt_create"		},
1844	{	t2,	"dns_rbt_addname 1"		},
1845	{	t3,	"dns_rbt_addname 2"		},
1846	{	t4,	"dns_rbt_deletename 1"		},
1847	{	t5,	"dns_rbt_deletename 2"		},
1848	{	t6,	"dns_rbt_findname 1"		},
1849	{	t7,	"dns_rbt_findname 2"		},
1850	{	t8,	"dns_rbt_findname 3"		},
1851	{	t9,	"dns_rbtnodechain_init"		},
1852	{	t10,	"dns_rbtnodechain_first"	},
1853	{	t11,	"dns_rbtnodechain_last"		},
1854	{	t12,	"dns_rbtnodechain_next"		},
1855	{	t13,	"dns_rbtnodechain_prev"		},
1856	{	NULL,	NULL				}
1857};
1858
1859