rdataset.c revision 193149
1181641Skmacy/*
2181641Skmacy * Copyright (C) 2004-2009  Internet Systems Consortium, Inc. ("ISC")
3181641Skmacy * Copyright (C) 1999-2003  Internet Software Consortium.
4181641Skmacy *
5181641Skmacy * Permission to use, copy, modify, and/or distribute this software for any
6181641Skmacy * purpose with or without fee is hereby granted, provided that the above
7181641Skmacy * copyright notice and this permission notice appear in all copies.
8181641Skmacy *
9181641Skmacy * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10181641Skmacy * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11181641Skmacy * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12181641Skmacy * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13181641Skmacy * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14181641Skmacy * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15181641Skmacy * PERFORMANCE OF THIS SOFTWARE.
16181641Skmacy */
17181641Skmacy
18181641Skmacy/* $Id: rdataset.c,v 1.82.50.2 2009/01/18 23:47:40 tbox Exp $ */
19181641Skmacy
20181641Skmacy/*! \file */
21181641Skmacy
22181641Skmacy#include <config.h>
23181641Skmacy
24181641Skmacy#include <stdlib.h>
25181641Skmacy
26181641Skmacy#include <isc/buffer.h>
27181641Skmacy#include <isc/mem.h>
28181641Skmacy#include <isc/random.h>
29181641Skmacy#include <isc/util.h>
30181641Skmacy
31181641Skmacy#include <dns/name.h>
32181641Skmacy#include <dns/ncache.h>
33181641Skmacy#include <dns/rdata.h>
34181641Skmacy#include <dns/rdataset.h>
35181641Skmacy#include <dns/compress.h>
36181641Skmacy
37181641Skmacyvoid
38181641Skmacydns_rdataset_init(dns_rdataset_t *rdataset) {
39181641Skmacy
40181641Skmacy	/*
41181641Skmacy	 * Make 'rdataset' a valid, disassociated rdataset.
42181641Skmacy	 */
43181641Skmacy
44181641Skmacy	REQUIRE(rdataset != NULL);
45181641Skmacy
46181641Skmacy	rdataset->magic = DNS_RDATASET_MAGIC;
47181641Skmacy	rdataset->methods = NULL;
48181641Skmacy	ISC_LINK_INIT(rdataset, link);
49181641Skmacy	rdataset->rdclass = 0;
50181641Skmacy	rdataset->type = 0;
51181641Skmacy	rdataset->ttl = 0;
52181641Skmacy	rdataset->trust = 0;
53181641Skmacy	rdataset->covers = 0;
54181641Skmacy	rdataset->attributes = 0;
55181641Skmacy	rdataset->count = ISC_UINT32_MAX;
56181641Skmacy	rdataset->private1 = NULL;
57181641Skmacy	rdataset->private2 = NULL;
58181641Skmacy	rdataset->private3 = NULL;
59181641Skmacy	rdataset->privateuint4 = 0;
60181641Skmacy	rdataset->private5 = NULL;
61181641Skmacy	rdataset->private6 = NULL;
62181641Skmacy	rdataset->resign = 0;
63181641Skmacy}
64181641Skmacy
65181641Skmacyvoid
66181641Skmacydns_rdataset_invalidate(dns_rdataset_t *rdataset) {
67181641Skmacy
68181641Skmacy	/*
69181641Skmacy	 * Invalidate 'rdataset'.
70181641Skmacy	 */
71181641Skmacy
72181641Skmacy	REQUIRE(DNS_RDATASET_VALID(rdataset));
73181641Skmacy	REQUIRE(rdataset->methods == NULL);
74181641Skmacy
75181641Skmacy	rdataset->magic = 0;
76181641Skmacy	ISC_LINK_INIT(rdataset, link);
77181641Skmacy	rdataset->rdclass = 0;
78181641Skmacy	rdataset->type = 0;
79181641Skmacy	rdataset->ttl = 0;
80181641Skmacy	rdataset->trust = 0;
81181641Skmacy	rdataset->covers = 0;
82181641Skmacy	rdataset->attributes = 0;
83181641Skmacy	rdataset->count = ISC_UINT32_MAX;
84181641Skmacy	rdataset->private1 = NULL;
85181641Skmacy	rdataset->private2 = NULL;
86181641Skmacy	rdataset->private3 = NULL;
87181641Skmacy	rdataset->privateuint4 = 0;
88181641Skmacy	rdataset->private5 = NULL;
89181641Skmacy}
90181641Skmacy
91181641Skmacyvoid
92181641Skmacydns_rdataset_disassociate(dns_rdataset_t *rdataset) {
93181641Skmacy
94181641Skmacy	/*
95181641Skmacy	 * Disassociate 'rdataset' from its rdata, allowing it to be reused.
96181641Skmacy	 */
97181641Skmacy
98181641Skmacy	REQUIRE(DNS_RDATASET_VALID(rdataset));
99181641Skmacy	REQUIRE(rdataset->methods != NULL);
100181641Skmacy
101181641Skmacy	(rdataset->methods->disassociate)(rdataset);
102181641Skmacy	rdataset->methods = NULL;
103181641Skmacy	ISC_LINK_INIT(rdataset, link);
104181641Skmacy	rdataset->rdclass = 0;
105181641Skmacy	rdataset->type = 0;
106181641Skmacy	rdataset->ttl = 0;
107181641Skmacy	rdataset->trust = 0;
108181641Skmacy	rdataset->covers = 0;
109181641Skmacy	rdataset->attributes = 0;
110181641Skmacy	rdataset->count = ISC_UINT32_MAX;
111181641Skmacy	rdataset->private1 = NULL;
112181641Skmacy	rdataset->private2 = NULL;
113181641Skmacy	rdataset->private3 = NULL;
114181641Skmacy	rdataset->privateuint4 = 0;
115181641Skmacy	rdataset->private5 = NULL;
116181641Skmacy	rdataset->private6 = NULL;
117181641Skmacy}
118181641Skmacy
119181641Skmacyisc_boolean_t
120181641Skmacydns_rdataset_isassociated(dns_rdataset_t *rdataset) {
121181641Skmacy	/*
122195949Skib	 * Is 'rdataset' associated?
123181641Skmacy	 */
124181641Skmacy
125181641Skmacy	REQUIRE(DNS_RDATASET_VALID(rdataset));
126181641Skmacy
127181641Skmacy	if (rdataset->methods != NULL)
128181641Skmacy		return (ISC_TRUE);
129181641Skmacy
130181641Skmacy	return (ISC_FALSE);
131181641Skmacy}
132181641Skmacy
133181641Skmacystatic void
134181641Skmacyquestion_disassociate(dns_rdataset_t *rdataset) {
135181641Skmacy	UNUSED(rdataset);
136181641Skmacy}
137181641Skmacy
138181641Skmacystatic isc_result_t
139181641Skmacyquestion_cursor(dns_rdataset_t *rdataset) {
140181641Skmacy	UNUSED(rdataset);
141181641Skmacy
142181641Skmacy	return (ISC_R_NOMORE);
143181641Skmacy}
144181641Skmacy
145181641Skmacystatic void
146181641Skmacyquestion_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
147181641Skmacy	/*
148181641Skmacy	 * This routine should never be called.
149181641Skmacy	 */
150181641Skmacy	UNUSED(rdataset);
151181641Skmacy	UNUSED(rdata);
152181641Skmacy
153181641Skmacy	REQUIRE(0);
154181641Skmacy}
155181641Skmacy
156186557Skmacystatic void
157181641Skmacyquestion_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
158181641Skmacy	*target = *source;
159181641Skmacy}
160181641Skmacy
161181641Skmacystatic unsigned int
162181641Skmacyquestion_count(dns_rdataset_t *rdataset) {
163181641Skmacy	/*
164181641Skmacy	 * This routine should never be called.
165181641Skmacy	 */
166181641Skmacy	UNUSED(rdataset);
167181641Skmacy	REQUIRE(0);
168181641Skmacy
169208651Salc	return (0);
170181641Skmacy}
171208651Salc
172204041Sedstatic dns_rdatasetmethods_t question_methods = {
173208651Salc	question_disassociate,
174204041Sed	question_cursor,
175202628Sed	question_cursor,
176204041Sed	question_current,
177181641Skmacy	question_clone,
178181641Skmacy	question_count,
179181641Skmacy	NULL,
180181641Skmacy	NULL,
181181641Skmacy	NULL,
182181641Skmacy	NULL,
183181641Skmacy	NULL,
184181641Skmacy	NULL,
185181641Skmacy	NULL
186181641Skmacy};
187181641Skmacy
188181747Skmacyvoid
189181747Skmacydns_rdataset_makequestion(dns_rdataset_t *rdataset, dns_rdataclass_t rdclass,
190181747Skmacy			  dns_rdatatype_t type)
191181641Skmacy{
192181641Skmacy
193181641Skmacy	/*
194181641Skmacy	 * Make 'rdataset' a valid, associated, question rdataset, with a
195181641Skmacy	 * question class of 'rdclass' and type 'type'.
196181641Skmacy	 */
197181641Skmacy
198181641Skmacy	REQUIRE(DNS_RDATASET_VALID(rdataset));
199181641Skmacy	REQUIRE(rdataset->methods == NULL);
200181641Skmacy
201181641Skmacy	rdataset->methods = &question_methods;
202181641Skmacy	rdataset->rdclass = rdclass;
203181641Skmacy	rdataset->type = type;
204181641Skmacy	rdataset->attributes |= DNS_RDATASETATTR_QUESTION;
205181641Skmacy}
206181641Skmacy
207181641Skmacyunsigned int
208181641Skmacydns_rdataset_count(dns_rdataset_t *rdataset) {
209181641Skmacy
210181641Skmacy	/*
211181641Skmacy	 * Return the number of records in 'rdataset'.
212181641Skmacy	 */
213181641Skmacy
214181641Skmacy	REQUIRE(DNS_RDATASET_VALID(rdataset));
215182902Skmacy	REQUIRE(rdataset->methods != NULL);
216181641Skmacy
217181641Skmacy	return ((rdataset->methods->count)(rdataset));
218181641Skmacy}
219181641Skmacy
220181641Skmacyvoid
221181641Skmacydns_rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
222181641Skmacy
223196726Sadrian	/*
224196726Sadrian	 * Make 'target' refer to the same rdataset as 'source'.
225181641Skmacy	 */
226181641Skmacy
227181641Skmacy	REQUIRE(DNS_RDATASET_VALID(source));
228181641Skmacy	REQUIRE(source->methods != NULL);
229181747Skmacy	REQUIRE(DNS_RDATASET_VALID(target));
230181641Skmacy	REQUIRE(target->methods == NULL);
231181641Skmacy
232181641Skmacy	(source->methods->clone)(source, target);
233181641Skmacy}
234181641Skmacy
235181641Skmacyisc_result_t
236181641Skmacydns_rdataset_first(dns_rdataset_t *rdataset) {
237181641Skmacy
238181641Skmacy	/*
239181641Skmacy	 * Move the rdata cursor to the first rdata in the rdataset (if any).
240181641Skmacy	 */
241181641Skmacy
242181641Skmacy	REQUIRE(DNS_RDATASET_VALID(rdataset));
243181641Skmacy	REQUIRE(rdataset->methods != NULL);
244181641Skmacy
245181641Skmacy	return ((rdataset->methods->first)(rdataset));
246181641Skmacy}
247181641Skmacy
248204160Skmacyisc_result_t
249181641Skmacydns_rdataset_next(dns_rdataset_t *rdataset) {
250181641Skmacy
251181641Skmacy	/*
252181641Skmacy	 * Move the rdata cursor to the next rdata in the rdataset (if any).
253181641Skmacy	 */
254181641Skmacy
255181641Skmacy	REQUIRE(DNS_RDATASET_VALID(rdataset));
256181641Skmacy	REQUIRE(rdataset->methods != NULL);
257181641Skmacy
258181641Skmacy	return ((rdataset->methods->next)(rdataset));
259181641Skmacy}
260181641Skmacy
261181641Skmacyvoid
262181641Skmacydns_rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
263181641Skmacy
264181641Skmacy	/*
265181641Skmacy	 * Make 'rdata' refer to the current rdata.
266181641Skmacy	 */
267181641Skmacy
268181641Skmacy	REQUIRE(DNS_RDATASET_VALID(rdataset));
269181641Skmacy	REQUIRE(rdataset->methods != NULL);
270181641Skmacy
271181641Skmacy	(rdataset->methods->current)(rdataset, rdata);
272181641Skmacy}
273181641Skmacy
274181641Skmacy#define MAX_SHUFFLE	32
275181641Skmacy#define WANT_FIXED(r)	(((r)->attributes & DNS_RDATASETATTR_FIXEDORDER) != 0)
276181747Skmacy#define WANT_RANDOM(r)	(((r)->attributes & DNS_RDATASETATTR_RANDOMIZE) != 0)
277181747Skmacy
278199184Savgstruct towire_sort {
279181747Skmacy	int key;
280181747Skmacy	dns_rdata_t *rdata;
281181747Skmacy};
282181747Skmacy
283181747Skmacystatic int
284181747Skmacytowire_compare(const void *av, const void *bv) {
285207419Skmacy	const struct towire_sort *a = (const struct towire_sort *) av;
286207419Skmacy	const struct towire_sort *b = (const struct towire_sort *) bv;
287181747Skmacy	return (a->key - b->key);
288207419Skmacy}
289207419Skmacy
290207419Skmacystatic isc_result_t
291207419Skmacytowiresorted(dns_rdataset_t *rdataset, const dns_name_t *owner_name,
292181641Skmacy	     dns_compress_t *cctx, isc_buffer_t *target,
293181641Skmacy	     dns_rdatasetorderfunc_t order, const void *order_arg,
294208651Salc	     isc_boolean_t partial, unsigned int options,
295208651Salc	     unsigned int *countp, void **state)
296208651Salc{
297181641Skmacy	dns_rdata_t rdata = DNS_RDATA_INIT;
298181641Skmacy	isc_region_t r;
299181641Skmacy	isc_result_t result;
300181641Skmacy	unsigned int i, count, added, choice;
301181641Skmacy	isc_buffer_t savedbuffer, rdlen, rrbuffer;
302181641Skmacy	unsigned int headlen;
303181641Skmacy	isc_boolean_t question = ISC_FALSE;
304181641Skmacy	isc_boolean_t shuffle = ISC_FALSE;
305181641Skmacy	dns_rdata_t *shuffled = NULL, shuffled_fixed[MAX_SHUFFLE];
306181641Skmacy	struct towire_sort *sorted = NULL, sorted_fixed[MAX_SHUFFLE];
307181641Skmacy
308181641Skmacy	UNUSED(state);
309181641Skmacy
310181641Skmacy	/*
311181641Skmacy	 * Convert 'rdataset' to wire format, compressing names as specified
312181641Skmacy	 * in cctx, and storing the result in 'target'.
313181641Skmacy	 */
314181641Skmacy
315181641Skmacy	REQUIRE(DNS_RDATASET_VALID(rdataset));
316181641Skmacy	REQUIRE(countp != NULL);
317181641Skmacy	REQUIRE((order == NULL) == (order_arg == NULL));
318181747Skmacy	REQUIRE(cctx != NULL && cctx->mctx != NULL);
319181641Skmacy
320196725Sadrian	count = 0;
321181747Skmacy	if ((rdataset->attributes & DNS_RDATASETATTR_QUESTION) != 0) {
322181641Skmacy		question = ISC_TRUE;
323181641Skmacy		count = 1;
324181641Skmacy		result = dns_rdataset_first(rdataset);
325181641Skmacy		INSIST(result == ISC_R_NOMORE);
326181641Skmacy	} else if (rdataset->type == 0) {
327181641Skmacy		/*
328181641Skmacy		 * This is a negative caching rdataset.
329181641Skmacy		 */
330181641Skmacy		unsigned int ncache_opts = 0;
331181641Skmacy		if ((options & DNS_RDATASETTOWIRE_OMITDNSSEC) != 0)
332181641Skmacy			ncache_opts |= DNS_NCACHETOWIRE_OMITDNSSEC;
333181641Skmacy		return (dns_ncache_towire(rdataset, cctx, target, ncache_opts,
334181641Skmacy					  countp));
335181641Skmacy	} else {
336181641Skmacy		count = (rdataset->methods->count)(rdataset);
337181641Skmacy		result = dns_rdataset_first(rdataset);
338181641Skmacy		if (result == ISC_R_NOMORE)
339181641Skmacy			return (ISC_R_SUCCESS);
340181641Skmacy		if (result != ISC_R_SUCCESS)
341181641Skmacy			return (result);
342181641Skmacy	}
343181641Skmacy
344181641Skmacy	/*
345181641Skmacy	 * Do we want to shuffle this answer?
346181641Skmacy	 */
347181641Skmacy	if (!question && count > 1 &&
348181641Skmacy	    (!WANT_FIXED(rdataset) || order != NULL) &&
349181641Skmacy	    rdataset->type != dns_rdatatype_rrsig)
350181641Skmacy		shuffle = ISC_TRUE;
351181641Skmacy
352181641Skmacy	if (shuffle && count > MAX_SHUFFLE) {
353181641Skmacy		shuffled = isc_mem_get(cctx->mctx, count * sizeof(*shuffled));
354181641Skmacy		sorted = isc_mem_get(cctx->mctx, count * sizeof(*sorted));
355181641Skmacy		if (shuffled == NULL || sorted == NULL)
356181641Skmacy			shuffle = ISC_FALSE;
357181641Skmacy	} else {
358181641Skmacy		shuffled = shuffled_fixed;
359181641Skmacy		sorted = sorted_fixed;
360181641Skmacy	}
361181641Skmacy
362181641Skmacy	if (shuffle) {
363181641Skmacy		/*
364181641Skmacy		 * First we get handles to all of the rdata.
365181641Skmacy		 */
366181641Skmacy		i = 0;
367181641Skmacy		do {
368181641Skmacy			INSIST(i < count);
369181641Skmacy			dns_rdata_init(&shuffled[i]);
370181641Skmacy			dns_rdataset_current(rdataset, &shuffled[i]);
371181641Skmacy			i++;
372181641Skmacy			result = dns_rdataset_next(rdataset);
373181641Skmacy		} while (result == ISC_R_SUCCESS);
374181641Skmacy		if (result != ISC_R_NOMORE)
375181641Skmacy			goto cleanup;
376181641Skmacy		INSIST(i == count);
377181641Skmacy
378181641Skmacy		/*
379181641Skmacy		 * Now we shuffle.
380181641Skmacy		 */
381181641Skmacy		if (WANT_FIXED(rdataset)) {
382181641Skmacy			/*
383181641Skmacy			 * 'Fixed' order.
384181641Skmacy			 */
385181641Skmacy			INSIST(order != NULL);
386181641Skmacy			for (i = 0; i < count; i++) {
387181641Skmacy				sorted[i].key = (*order)(&shuffled[i],
388181641Skmacy							 order_arg);
389181641Skmacy				sorted[i].rdata = &shuffled[i];
390181641Skmacy			}
391181641Skmacy		} else if (WANT_RANDOM(rdataset)) {
392181641Skmacy			/*
393181641Skmacy			 * 'Random' order.
394181641Skmacy			 */
395181641Skmacy			for (i = 0; i < count; i++) {
396181641Skmacy				dns_rdata_t rdata;
397181641Skmacy				isc_uint32_t val;
398181641Skmacy
399181641Skmacy				isc_random_get(&val);
400181641Skmacy				choice = i + (val % (count - i));
401181641Skmacy				rdata = shuffled[i];
402181641Skmacy				shuffled[i] = shuffled[choice];
403181641Skmacy				shuffled[choice] = rdata;
404181641Skmacy				if (order != NULL)
405181641Skmacy					sorted[i].key = (*order)(&shuffled[i],
406181641Skmacy								 order_arg);
407181641Skmacy				else
408181641Skmacy					sorted[i].key = 0; /* Unused */
409181641Skmacy				sorted[i].rdata = &shuffled[i];
410181641Skmacy			}
411181641Skmacy		} else {
412181641Skmacy			/*
413181641Skmacy			 * "Cyclic" order.
414181641Skmacy			 */
415181641Skmacy			isc_uint32_t val;
416181641Skmacy			unsigned int j;
417181641Skmacy
418181641Skmacy			val = rdataset->count;
419181641Skmacy			if (val == ISC_UINT32_MAX)
420181641Skmacy				isc_random_get(&val);
421181641Skmacy			j = val % count;
422181641Skmacy			for (i = 0; i < count; i++) {
423181641Skmacy				if (order != NULL)
424181641Skmacy					sorted[j].key = (*order)(&shuffled[i],
425181641Skmacy								 order_arg);
426181641Skmacy				else
427181641Skmacy					sorted[j].key = 0; /* Unused */
428183342Skmacy				sorted[j].rdata = &shuffled[i];
429183342Skmacy				j++;
430181641Skmacy				if (j == count)
431181641Skmacy					j = 0; /* Wrap around. */
432181641Skmacy			}
433181641Skmacy		}
434181641Skmacy
435181641Skmacy		/*
436181641Skmacy		 * Sorted order.
437181641Skmacy		 */
438181641Skmacy		if (order != NULL)
439181641Skmacy			qsort(sorted, count, sizeof(sorted[0]),
440181641Skmacy			      towire_compare);
441181641Skmacy	}
442181641Skmacy
443181641Skmacy	savedbuffer = *target;
444181641Skmacy	i = 0;
445181641Skmacy	added = 0;
446181641Skmacy
447181641Skmacy	do {
448181641Skmacy		/*
449181641Skmacy		 * Copy out the name, type, class, ttl.
450204160Skmacy		 */
451204160Skmacy
452181641Skmacy		rrbuffer = *target;
453181641Skmacy		dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
454181641Skmacy		result = dns_name_towire(owner_name, cctx, target);
455181641Skmacy		if (result != ISC_R_SUCCESS)
456181641Skmacy			goto rollback;
457181641Skmacy		headlen = sizeof(dns_rdataclass_t) + sizeof(dns_rdatatype_t);
458181641Skmacy		if (!question)
459181641Skmacy			headlen += sizeof(dns_ttl_t)
460181641Skmacy				+ 2;  /* XXX 2 for rdata len */
461181641Skmacy		isc_buffer_availableregion(target, &r);
462181641Skmacy		if (r.length < headlen) {
463181641Skmacy			result = ISC_R_NOSPACE;
464181641Skmacy			goto rollback;
465181641Skmacy		}
466181641Skmacy		isc_buffer_putuint16(target, rdataset->type);
467181641Skmacy		isc_buffer_putuint16(target, rdataset->rdclass);
468181641Skmacy		if (!question) {
469181641Skmacy			isc_buffer_putuint32(target, rdataset->ttl);
470181641Skmacy
471181641Skmacy			/*
472181641Skmacy			 * Save space for rdlen.
473181641Skmacy			 */
474181641Skmacy			rdlen = *target;
475181641Skmacy			isc_buffer_add(target, 2);
476181641Skmacy
477181641Skmacy			/*
478181641Skmacy			 * Copy out the rdata
479181641Skmacy			 */
480181641Skmacy			if (shuffle)
481181641Skmacy				rdata = *(sorted[i].rdata);
482181641Skmacy			else {
483181641Skmacy				dns_rdata_reset(&rdata);
484181641Skmacy				dns_rdataset_current(rdataset, &rdata);
485181641Skmacy			}
486181641Skmacy			result = dns_rdata_towire(&rdata, cctx, target);
487181641Skmacy			if (result != ISC_R_SUCCESS)
488181641Skmacy				goto rollback;
489181641Skmacy			INSIST((target->used >= rdlen.used + 2) &&
490181641Skmacy			       (target->used - rdlen.used - 2 < 65536));
491181641Skmacy			isc_buffer_putuint16(&rdlen,
492181641Skmacy					     (isc_uint16_t)(target->used -
493181641Skmacy							    rdlen.used - 2));
494181641Skmacy			added++;
495181641Skmacy		}
496181641Skmacy
497181641Skmacy		if (shuffle) {
498181641Skmacy			i++;
499181641Skmacy			if (i == count)
500181641Skmacy				result = ISC_R_NOMORE;
501181641Skmacy			else
502181641Skmacy				result = ISC_R_SUCCESS;
503181641Skmacy		} else {
504181641Skmacy			result = dns_rdataset_next(rdataset);
505181641Skmacy		}
506181641Skmacy	} while (result == ISC_R_SUCCESS);
507181641Skmacy
508181641Skmacy	if (result != ISC_R_NOMORE)
509181641Skmacy		goto rollback;
510181641Skmacy
511181641Skmacy	*countp += count;
512181641Skmacy
513181641Skmacy	result = ISC_R_SUCCESS;
514181641Skmacy	goto cleanup;
515181641Skmacy
516181641Skmacy rollback:
517181641Skmacy	if (partial && result == ISC_R_NOSPACE) {
518181641Skmacy		INSIST(rrbuffer.used < 65536);
519196726Sadrian		dns_compress_rollback(cctx, (isc_uint16_t)rrbuffer.used);
520197070Sjkim		*countp += added;
521196726Sadrian		*target = rrbuffer;
522196726Sadrian		goto cleanup;
523196726Sadrian	}
524196726Sadrian	INSIST(savedbuffer.used < 65536);
525196726Sadrian	dns_compress_rollback(cctx, (isc_uint16_t)savedbuffer.used);
526196726Sadrian	*countp = 0;
527196726Sadrian	*target = savedbuffer;
528196726Sadrian
529196726Sadrian cleanup:
530196726Sadrian	if (sorted != NULL && sorted != sorted_fixed)
531196726Sadrian		isc_mem_put(cctx->mctx, sorted, count * sizeof(*sorted));
532196726Sadrian	if (shuffled != NULL && shuffled != shuffled_fixed)
533196726Sadrian		isc_mem_put(cctx->mctx, shuffled, count * sizeof(*shuffled));
534196726Sadrian	return (result);
535196726Sadrian}
536196726Sadrian
537196726Sadrianisc_result_t
538196726Sadriandns_rdataset_towiresorted(dns_rdataset_t *rdataset,
539196726Sadrian			  const dns_name_t *owner_name,
540196726Sadrian			  dns_compress_t *cctx,
541196726Sadrian			  isc_buffer_t *target,
542196726Sadrian			  dns_rdatasetorderfunc_t order,
543196726Sadrian			  const void *order_arg,
544196726Sadrian			  unsigned int options,
545196726Sadrian			  unsigned int *countp)
546196726Sadrian{
547196726Sadrian	return (towiresorted(rdataset, owner_name, cctx, target,
548196726Sadrian			     order, order_arg, ISC_FALSE, options,
549181641Skmacy			     countp, NULL));
550181641Skmacy}
551181641Skmacy
552181641Skmacyisc_result_t
553181641Skmacydns_rdataset_towirepartial(dns_rdataset_t *rdataset,
554181641Skmacy			   const dns_name_t *owner_name,
555181641Skmacy			   dns_compress_t *cctx,
556181641Skmacy			   isc_buffer_t *target,
557181641Skmacy			   dns_rdatasetorderfunc_t order,
558181641Skmacy			   const void *order_arg,
559181641Skmacy			   unsigned int options,
560195649Salc			   unsigned int *countp,
561181641Skmacy			   void **state)
562181641Skmacy{
563181641Skmacy	REQUIRE(state == NULL);	/* XXX remove when implemented */
564181641Skmacy	return (towiresorted(rdataset, owner_name, cctx, target,
565181641Skmacy			     order, order_arg, ISC_TRUE, options,
566181641Skmacy			     countp, state));
567181641Skmacy}
568181641Skmacy
569181641Skmacyisc_result_t
570181641Skmacydns_rdataset_towire(dns_rdataset_t *rdataset,
571181641Skmacy		    dns_name_t *owner_name,
572181641Skmacy		    dns_compress_t *cctx,
573181641Skmacy		    isc_buffer_t *target,
574181641Skmacy		    unsigned int options,
575181641Skmacy		    unsigned int *countp)
576181641Skmacy{
577181641Skmacy	return (towiresorted(rdataset, owner_name, cctx, target,
578181641Skmacy			     NULL, NULL, ISC_FALSE, options, countp, NULL));
579181641Skmacy}
580181641Skmacy
581181641Skmacyisc_result_t
582181641Skmacydns_rdataset_additionaldata(dns_rdataset_t *rdataset,
583181641Skmacy			    dns_additionaldatafunc_t add, void *arg)
584181641Skmacy{
585181641Skmacy	dns_rdata_t rdata = DNS_RDATA_INIT;
586181641Skmacy	isc_result_t result;
587181641Skmacy
588181641Skmacy	/*
589181641Skmacy	 * For each rdata in rdataset, call 'add' for each name and type in the
590181641Skmacy	 * rdata which is subject to additional section processing.
591181641Skmacy	 */
592181641Skmacy
593181641Skmacy	REQUIRE(DNS_RDATASET_VALID(rdataset));
594181641Skmacy	REQUIRE((rdataset->attributes & DNS_RDATASETATTR_QUESTION) == 0);
595181641Skmacy
596181641Skmacy	result = dns_rdataset_first(rdataset);
597181641Skmacy	if (result != ISC_R_SUCCESS)
598181641Skmacy		return (result);
599181641Skmacy
600181641Skmacy	do {
601181641Skmacy		dns_rdataset_current(rdataset, &rdata);
602181641Skmacy		result = dns_rdata_additionaldata(&rdata, add, arg);
603181641Skmacy		if (result == ISC_R_SUCCESS)
604181641Skmacy			result = dns_rdataset_next(rdataset);
605181641Skmacy		dns_rdata_reset(&rdata);
606181641Skmacy	} while (result == ISC_R_SUCCESS);
607181641Skmacy
608181641Skmacy	if (result != ISC_R_NOMORE)
609181641Skmacy		return (result);
610181641Skmacy
611181641Skmacy	return (ISC_R_SUCCESS);
612181641Skmacy}
613181641Skmacy
614181641Skmacyisc_result_t
615181641Skmacydns_rdataset_addnoqname(dns_rdataset_t *rdataset, dns_name_t *name) {
616181641Skmacy
617181641Skmacy	REQUIRE(DNS_RDATASET_VALID(rdataset));
618181641Skmacy	REQUIRE(rdataset->methods != NULL);
619181641Skmacy	if (rdataset->methods->addnoqname == NULL)
620181641Skmacy		return (ISC_R_NOTIMPLEMENTED);
621181641Skmacy	return((rdataset->methods->addnoqname)(rdataset, name));
622181641Skmacy}
623181641Skmacy
624181641Skmacyisc_result_t
625181641Skmacydns_rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
626181641Skmacy			dns_rdataset_t *neg, dns_rdataset_t *negsig)
627181641Skmacy{
628181641Skmacy	REQUIRE(DNS_RDATASET_VALID(rdataset));
629181641Skmacy	REQUIRE(rdataset->methods != NULL);
630181641Skmacy
631181747Skmacy	if (rdataset->methods->getnoqname == NULL)
632181747Skmacy		return (ISC_R_NOTIMPLEMENTED);
633181747Skmacy	return((rdataset->methods->getnoqname)(rdataset, name, neg, negsig));
634181641Skmacy}
635181641Skmacy
636181747Skmacyisc_result_t
637181747Skmacydns_rdataset_addclosest(dns_rdataset_t *rdataset, dns_name_t *name) {
638181747Skmacy
639181747Skmacy	REQUIRE(DNS_RDATASET_VALID(rdataset));
640181808Skmacy	REQUIRE(rdataset->methods != NULL);
641181747Skmacy	if (rdataset->methods->addclosest == NULL)
642181747Skmacy		return (ISC_R_NOTIMPLEMENTED);
643181747Skmacy	return((rdataset->methods->addclosest)(rdataset, name));
644181747Skmacy}
645181808Skmacy
646181747Skmacyisc_result_t
647181747Skmacydns_rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name,
648181747Skmacy			dns_rdataset_t *neg, dns_rdataset_t *negsig)
649181641Skmacy{
650181641Skmacy	REQUIRE(DNS_RDATASET_VALID(rdataset));
651181641Skmacy	REQUIRE(rdataset->methods != NULL);
652181641Skmacy
653181641Skmacy	if (rdataset->methods->getclosest == NULL)
654181641Skmacy		return (ISC_R_NOTIMPLEMENTED);
655181641Skmacy	return((rdataset->methods->getclosest)(rdataset, name, neg, negsig));
656181641Skmacy}
657181641Skmacy
658181641Skmacy/*
659181747Skmacy * Additional cache stuff
660181747Skmacy */
661181747Skmacyisc_result_t
662181747Skmacydns_rdataset_getadditional(dns_rdataset_t *rdataset,
663181747Skmacy			   dns_rdatasetadditional_t type,
664181747Skmacy			   dns_rdatatype_t qtype,
665181747Skmacy			   dns_acache_t *acache,
666181747Skmacy			   dns_zone_t **zonep,
667181747Skmacy			   dns_db_t **dbp,
668181747Skmacy			   dns_dbversion_t **versionp,
669181747Skmacy			   dns_dbnode_t **nodep,
670181747Skmacy			   dns_name_t *fname,
671181747Skmacy			   dns_message_t *msg,
672181747Skmacy			   isc_stdtime_t now)
673181747Skmacy{
674181747Skmacy	REQUIRE(DNS_RDATASET_VALID(rdataset));
675181747Skmacy	REQUIRE(rdataset->methods != NULL);
676181747Skmacy	REQUIRE(zonep == NULL || *zonep == NULL);
677181747Skmacy	REQUIRE(dbp != NULL && *dbp == NULL);
678181747Skmacy	REQUIRE(versionp != NULL && *versionp == NULL);
679181641Skmacy	REQUIRE(nodep != NULL && *nodep == NULL);
680181641Skmacy	REQUIRE(fname != NULL);
681181641Skmacy	REQUIRE(msg != NULL);
682181641Skmacy
683181641Skmacy	if (acache != NULL && rdataset->methods->getadditional != NULL) {
684181641Skmacy		return ((rdataset->methods->getadditional)(rdataset, type,
685181641Skmacy							   qtype, acache,
686181641Skmacy							   zonep, dbp,
687181641Skmacy							   versionp, nodep,
688181641Skmacy							   fname, msg, now));
689181641Skmacy	}
690181641Skmacy
691181641Skmacy	return (ISC_R_FAILURE);
692181641Skmacy}
693181641Skmacy
694181641Skmacyisc_result_t
695181641Skmacydns_rdataset_setadditional(dns_rdataset_t *rdataset,
696195949Skib			   dns_rdatasetadditional_t type,
697181641Skmacy			   dns_rdatatype_t qtype,
698181641Skmacy			   dns_acache_t *acache,
699181641Skmacy			   dns_zone_t *zone,
700181641Skmacy			   dns_db_t *db,
701181641Skmacy			   dns_dbversion_t *version,
702181641Skmacy			   dns_dbnode_t *node,
703181641Skmacy			   dns_name_t *fname)
704181641Skmacy{
705181641Skmacy	REQUIRE(DNS_RDATASET_VALID(rdataset));
706181641Skmacy	REQUIRE(rdataset->methods != NULL);
707181641Skmacy
708181641Skmacy	if (acache != NULL && rdataset->methods->setadditional != NULL) {
709181641Skmacy		return ((rdataset->methods->setadditional)(rdataset, type,
710181641Skmacy							   qtype, acache, zone,
711181641Skmacy							   db, version,
712181641Skmacy							   node, fname));
713181641Skmacy	}
714181641Skmacy
715181641Skmacy	return (ISC_R_FAILURE);
716181641Skmacy}
717181641Skmacy
718181641Skmacyisc_result_t
719181641Skmacydns_rdataset_putadditional(dns_acache_t *acache,
720196726Sadrian			   dns_rdataset_t *rdataset,
721196726Sadrian			   dns_rdatasetadditional_t type,
722196726Sadrian			   dns_rdatatype_t qtype)
723196726Sadrian{
724196726Sadrian	REQUIRE(DNS_RDATASET_VALID(rdataset));
725196726Sadrian	REQUIRE(rdataset->methods != NULL);
726196726Sadrian
727196726Sadrian	if (acache != NULL && rdataset->methods->putadditional != NULL) {
728196726Sadrian		return ((rdataset->methods->putadditional)(acache, rdataset,
729196726Sadrian							   type, qtype));
730196726Sadrian	}
731196726Sadrian
732196726Sadrian	return (ISC_R_FAILURE);
733196726Sadrian}
734196726Sadrian
735196726Sadrian