Sync usage with man page.
[netbsd-mini2440.git] / external / bsd / bind / dist / lib / dns / rdataset.c
blobf134f01e94ec5d567f8de229ee1ab3df356ed153
1 /* $NetBSD$ */
3 /*
4 * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1999-2003 Internet Software Consortium.
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.
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.
20 /* Id: rdataset.c,v 1.84 2009/01/17 23:47:43 tbox Exp */
22 /*! \file */
24 #include <config.h>
26 #include <stdlib.h>
28 #include <isc/buffer.h>
29 #include <isc/mem.h>
30 #include <isc/random.h>
31 #include <isc/util.h>
33 #include <dns/name.h>
34 #include <dns/ncache.h>
35 #include <dns/rdata.h>
36 #include <dns/rdataset.h>
37 #include <dns/compress.h>
39 void
40 dns_rdataset_init(dns_rdataset_t *rdataset) {
43 * Make 'rdataset' a valid, disassociated rdataset.
46 REQUIRE(rdataset != NULL);
48 rdataset->magic = DNS_RDATASET_MAGIC;
49 rdataset->methods = NULL;
50 ISC_LINK_INIT(rdataset, link);
51 rdataset->rdclass = 0;
52 rdataset->type = 0;
53 rdataset->ttl = 0;
54 rdataset->trust = 0;
55 rdataset->covers = 0;
56 rdataset->attributes = 0;
57 rdataset->count = ISC_UINT32_MAX;
58 rdataset->private1 = NULL;
59 rdataset->private2 = NULL;
60 rdataset->private3 = NULL;
61 rdataset->privateuint4 = 0;
62 rdataset->private5 = NULL;
63 rdataset->private6 = NULL;
64 rdataset->resign = 0;
67 void
68 dns_rdataset_invalidate(dns_rdataset_t *rdataset) {
71 * Invalidate 'rdataset'.
74 REQUIRE(DNS_RDATASET_VALID(rdataset));
75 REQUIRE(rdataset->methods == NULL);
77 rdataset->magic = 0;
78 ISC_LINK_INIT(rdataset, link);
79 rdataset->rdclass = 0;
80 rdataset->type = 0;
81 rdataset->ttl = 0;
82 rdataset->trust = 0;
83 rdataset->covers = 0;
84 rdataset->attributes = 0;
85 rdataset->count = ISC_UINT32_MAX;
86 rdataset->private1 = NULL;
87 rdataset->private2 = NULL;
88 rdataset->private3 = NULL;
89 rdataset->privateuint4 = 0;
90 rdataset->private5 = NULL;
93 void
94 dns_rdataset_disassociate(dns_rdataset_t *rdataset) {
97 * Disassociate 'rdataset' from its rdata, allowing it to be reused.
100 REQUIRE(DNS_RDATASET_VALID(rdataset));
101 REQUIRE(rdataset->methods != NULL);
103 (rdataset->methods->disassociate)(rdataset);
104 rdataset->methods = NULL;
105 ISC_LINK_INIT(rdataset, link);
106 rdataset->rdclass = 0;
107 rdataset->type = 0;
108 rdataset->ttl = 0;
109 rdataset->trust = 0;
110 rdataset->covers = 0;
111 rdataset->attributes = 0;
112 rdataset->count = ISC_UINT32_MAX;
113 rdataset->private1 = NULL;
114 rdataset->private2 = NULL;
115 rdataset->private3 = NULL;
116 rdataset->privateuint4 = 0;
117 rdataset->private5 = NULL;
118 rdataset->private6 = NULL;
121 isc_boolean_t
122 dns_rdataset_isassociated(dns_rdataset_t *rdataset) {
124 * Is 'rdataset' associated?
127 REQUIRE(DNS_RDATASET_VALID(rdataset));
129 if (rdataset->methods != NULL)
130 return (ISC_TRUE);
132 return (ISC_FALSE);
135 static void
136 question_disassociate(dns_rdataset_t *rdataset) {
137 UNUSED(rdataset);
140 static isc_result_t
141 question_cursor(dns_rdataset_t *rdataset) {
142 UNUSED(rdataset);
144 return (ISC_R_NOMORE);
147 static void
148 question_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
150 * This routine should never be called.
152 UNUSED(rdataset);
153 UNUSED(rdata);
155 REQUIRE(0);
158 static void
159 question_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
160 *target = *source;
163 static unsigned int
164 question_count(dns_rdataset_t *rdataset) {
166 * This routine should never be called.
168 UNUSED(rdataset);
169 REQUIRE(0);
171 return (0);
174 static dns_rdatasetmethods_t question_methods = {
175 question_disassociate,
176 question_cursor,
177 question_cursor,
178 question_current,
179 question_clone,
180 question_count,
181 NULL,
182 NULL,
183 NULL,
184 NULL,
185 NULL,
186 NULL,
187 NULL
190 void
191 dns_rdataset_makequestion(dns_rdataset_t *rdataset, dns_rdataclass_t rdclass,
192 dns_rdatatype_t type)
196 * Make 'rdataset' a valid, associated, question rdataset, with a
197 * question class of 'rdclass' and type 'type'.
200 REQUIRE(DNS_RDATASET_VALID(rdataset));
201 REQUIRE(rdataset->methods == NULL);
203 rdataset->methods = &question_methods;
204 rdataset->rdclass = rdclass;
205 rdataset->type = type;
206 rdataset->attributes |= DNS_RDATASETATTR_QUESTION;
209 unsigned int
210 dns_rdataset_count(dns_rdataset_t *rdataset) {
213 * Return the number of records in 'rdataset'.
216 REQUIRE(DNS_RDATASET_VALID(rdataset));
217 REQUIRE(rdataset->methods != NULL);
219 return ((rdataset->methods->count)(rdataset));
222 void
223 dns_rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
226 * Make 'target' refer to the same rdataset as 'source'.
229 REQUIRE(DNS_RDATASET_VALID(source));
230 REQUIRE(source->methods != NULL);
231 REQUIRE(DNS_RDATASET_VALID(target));
232 REQUIRE(target->methods == NULL);
234 (source->methods->clone)(source, target);
237 isc_result_t
238 dns_rdataset_first(dns_rdataset_t *rdataset) {
241 * Move the rdata cursor to the first rdata in the rdataset (if any).
244 REQUIRE(DNS_RDATASET_VALID(rdataset));
245 REQUIRE(rdataset->methods != NULL);
247 return ((rdataset->methods->first)(rdataset));
250 isc_result_t
251 dns_rdataset_next(dns_rdataset_t *rdataset) {
254 * Move the rdata cursor to the next rdata in the rdataset (if any).
257 REQUIRE(DNS_RDATASET_VALID(rdataset));
258 REQUIRE(rdataset->methods != NULL);
260 return ((rdataset->methods->next)(rdataset));
263 void
264 dns_rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
267 * Make 'rdata' refer to the current rdata.
270 REQUIRE(DNS_RDATASET_VALID(rdataset));
271 REQUIRE(rdataset->methods != NULL);
273 (rdataset->methods->current)(rdataset, rdata);
276 #define MAX_SHUFFLE 32
277 #define WANT_FIXED(r) (((r)->attributes & DNS_RDATASETATTR_FIXEDORDER) != 0)
278 #define WANT_RANDOM(r) (((r)->attributes & DNS_RDATASETATTR_RANDOMIZE) != 0)
280 struct towire_sort {
281 int key;
282 dns_rdata_t *rdata;
285 static int
286 towire_compare(const void *av, const void *bv) {
287 const struct towire_sort *a = (const struct towire_sort *) av;
288 const struct towire_sort *b = (const struct towire_sort *) bv;
289 return (a->key - b->key);
292 static isc_result_t
293 towiresorted(dns_rdataset_t *rdataset, const dns_name_t *owner_name,
294 dns_compress_t *cctx, isc_buffer_t *target,
295 dns_rdatasetorderfunc_t order, const void *order_arg,
296 isc_boolean_t partial, unsigned int options,
297 unsigned int *countp, void **state)
299 dns_rdata_t rdata = DNS_RDATA_INIT;
300 isc_region_t r;
301 isc_result_t result;
302 unsigned int i, count, added, choice;
303 isc_buffer_t savedbuffer, rdlen, rrbuffer;
304 unsigned int headlen;
305 isc_boolean_t question = ISC_FALSE;
306 isc_boolean_t shuffle = ISC_FALSE;
307 dns_rdata_t *shuffled = NULL, shuffled_fixed[MAX_SHUFFLE];
308 struct towire_sort *sorted = NULL, sorted_fixed[MAX_SHUFFLE];
310 UNUSED(state);
313 * Convert 'rdataset' to wire format, compressing names as specified
314 * in cctx, and storing the result in 'target'.
317 REQUIRE(DNS_RDATASET_VALID(rdataset));
318 REQUIRE(countp != NULL);
319 REQUIRE((order == NULL) == (order_arg == NULL));
320 REQUIRE(cctx != NULL && cctx->mctx != NULL);
322 count = 0;
323 if ((rdataset->attributes & DNS_RDATASETATTR_QUESTION) != 0) {
324 question = ISC_TRUE;
325 count = 1;
326 result = dns_rdataset_first(rdataset);
327 INSIST(result == ISC_R_NOMORE);
328 } else if (rdataset->type == 0) {
330 * This is a negative caching rdataset.
332 unsigned int ncache_opts = 0;
333 if ((options & DNS_RDATASETTOWIRE_OMITDNSSEC) != 0)
334 ncache_opts |= DNS_NCACHETOWIRE_OMITDNSSEC;
335 return (dns_ncache_towire(rdataset, cctx, target, ncache_opts,
336 countp));
337 } else {
338 count = (rdataset->methods->count)(rdataset);
339 result = dns_rdataset_first(rdataset);
340 if (result == ISC_R_NOMORE)
341 return (ISC_R_SUCCESS);
342 if (result != ISC_R_SUCCESS)
343 return (result);
347 * Do we want to shuffle this answer?
349 if (!question && count > 1 &&
350 (!WANT_FIXED(rdataset) || order != NULL) &&
351 rdataset->type != dns_rdatatype_rrsig)
352 shuffle = ISC_TRUE;
354 if (shuffle && count > MAX_SHUFFLE) {
355 shuffled = isc_mem_get(cctx->mctx, count * sizeof(*shuffled));
356 sorted = isc_mem_get(cctx->mctx, count * sizeof(*sorted));
357 if (shuffled == NULL || sorted == NULL)
358 shuffle = ISC_FALSE;
359 } else {
360 shuffled = shuffled_fixed;
361 sorted = sorted_fixed;
364 if (shuffle) {
366 * First we get handles to all of the rdata.
368 i = 0;
369 do {
370 INSIST(i < count);
371 dns_rdata_init(&shuffled[i]);
372 dns_rdataset_current(rdataset, &shuffled[i]);
373 i++;
374 result = dns_rdataset_next(rdataset);
375 } while (result == ISC_R_SUCCESS);
376 if (result != ISC_R_NOMORE)
377 goto cleanup;
378 INSIST(i == count);
381 * Now we shuffle.
383 if (WANT_FIXED(rdataset)) {
385 * 'Fixed' order.
387 INSIST(order != NULL);
388 for (i = 0; i < count; i++) {
389 sorted[i].key = (*order)(&shuffled[i],
390 order_arg);
391 sorted[i].rdata = &shuffled[i];
393 } else if (WANT_RANDOM(rdataset)) {
395 * 'Random' order.
397 for (i = 0; i < count; i++) {
398 dns_rdata_t rdata;
399 isc_uint32_t val;
401 isc_random_get(&val);
402 choice = i + (val % (count - i));
403 rdata = shuffled[i];
404 shuffled[i] = shuffled[choice];
405 shuffled[choice] = rdata;
406 if (order != NULL)
407 sorted[i].key = (*order)(&shuffled[i],
408 order_arg);
409 else
410 sorted[i].key = 0; /* Unused */
411 sorted[i].rdata = &shuffled[i];
413 } else {
415 * "Cyclic" order.
417 isc_uint32_t val;
418 unsigned int j;
420 val = rdataset->count;
421 if (val == ISC_UINT32_MAX)
422 isc_random_get(&val);
423 j = val % count;
424 for (i = 0; i < count; i++) {
425 if (order != NULL)
426 sorted[j].key = (*order)(&shuffled[i],
427 order_arg);
428 else
429 sorted[j].key = 0; /* Unused */
430 sorted[j].rdata = &shuffled[i];
431 j++;
432 if (j == count)
433 j = 0; /* Wrap around. */
438 * Sorted order.
440 if (order != NULL)
441 qsort(sorted, count, sizeof(sorted[0]),
442 towire_compare);
445 savedbuffer = *target;
446 i = 0;
447 added = 0;
449 do {
451 * Copy out the name, type, class, ttl.
454 rrbuffer = *target;
455 dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
456 result = dns_name_towire(owner_name, cctx, target);
457 if (result != ISC_R_SUCCESS)
458 goto rollback;
459 headlen = sizeof(dns_rdataclass_t) + sizeof(dns_rdatatype_t);
460 if (!question)
461 headlen += sizeof(dns_ttl_t)
462 + 2; /* XXX 2 for rdata len */
463 isc_buffer_availableregion(target, &r);
464 if (r.length < headlen) {
465 result = ISC_R_NOSPACE;
466 goto rollback;
468 isc_buffer_putuint16(target, rdataset->type);
469 isc_buffer_putuint16(target, rdataset->rdclass);
470 if (!question) {
471 isc_buffer_putuint32(target, rdataset->ttl);
474 * Save space for rdlen.
476 rdlen = *target;
477 isc_buffer_add(target, 2);
480 * Copy out the rdata
482 if (shuffle)
483 rdata = *(sorted[i].rdata);
484 else {
485 dns_rdata_reset(&rdata);
486 dns_rdataset_current(rdataset, &rdata);
488 result = dns_rdata_towire(&rdata, cctx, target);
489 if (result != ISC_R_SUCCESS)
490 goto rollback;
491 INSIST((target->used >= rdlen.used + 2) &&
492 (target->used - rdlen.used - 2 < 65536));
493 isc_buffer_putuint16(&rdlen,
494 (isc_uint16_t)(target->used -
495 rdlen.used - 2));
496 added++;
499 if (shuffle) {
500 i++;
501 if (i == count)
502 result = ISC_R_NOMORE;
503 else
504 result = ISC_R_SUCCESS;
505 } else {
506 result = dns_rdataset_next(rdataset);
508 } while (result == ISC_R_SUCCESS);
510 if (result != ISC_R_NOMORE)
511 goto rollback;
513 *countp += count;
515 result = ISC_R_SUCCESS;
516 goto cleanup;
518 rollback:
519 if (partial && result == ISC_R_NOSPACE) {
520 INSIST(rrbuffer.used < 65536);
521 dns_compress_rollback(cctx, (isc_uint16_t)rrbuffer.used);
522 *countp += added;
523 *target = rrbuffer;
524 goto cleanup;
526 INSIST(savedbuffer.used < 65536);
527 dns_compress_rollback(cctx, (isc_uint16_t)savedbuffer.used);
528 *countp = 0;
529 *target = savedbuffer;
531 cleanup:
532 if (sorted != NULL && sorted != sorted_fixed)
533 isc_mem_put(cctx->mctx, sorted, count * sizeof(*sorted));
534 if (shuffled != NULL && shuffled != shuffled_fixed)
535 isc_mem_put(cctx->mctx, shuffled, count * sizeof(*shuffled));
536 return (result);
539 isc_result_t
540 dns_rdataset_towiresorted(dns_rdataset_t *rdataset,
541 const dns_name_t *owner_name,
542 dns_compress_t *cctx,
543 isc_buffer_t *target,
544 dns_rdatasetorderfunc_t order,
545 const void *order_arg,
546 unsigned int options,
547 unsigned int *countp)
549 return (towiresorted(rdataset, owner_name, cctx, target,
550 order, order_arg, ISC_FALSE, options,
551 countp, NULL));
554 isc_result_t
555 dns_rdataset_towirepartial(dns_rdataset_t *rdataset,
556 const dns_name_t *owner_name,
557 dns_compress_t *cctx,
558 isc_buffer_t *target,
559 dns_rdatasetorderfunc_t order,
560 const void *order_arg,
561 unsigned int options,
562 unsigned int *countp,
563 void **state)
565 REQUIRE(state == NULL); /* XXX remove when implemented */
566 return (towiresorted(rdataset, owner_name, cctx, target,
567 order, order_arg, ISC_TRUE, options,
568 countp, state));
571 isc_result_t
572 dns_rdataset_towire(dns_rdataset_t *rdataset,
573 dns_name_t *owner_name,
574 dns_compress_t *cctx,
575 isc_buffer_t *target,
576 unsigned int options,
577 unsigned int *countp)
579 return (towiresorted(rdataset, owner_name, cctx, target,
580 NULL, NULL, ISC_FALSE, options, countp, NULL));
583 isc_result_t
584 dns_rdataset_additionaldata(dns_rdataset_t *rdataset,
585 dns_additionaldatafunc_t add, void *arg)
587 dns_rdata_t rdata = DNS_RDATA_INIT;
588 isc_result_t result;
591 * For each rdata in rdataset, call 'add' for each name and type in the
592 * rdata which is subject to additional section processing.
595 REQUIRE(DNS_RDATASET_VALID(rdataset));
596 REQUIRE((rdataset->attributes & DNS_RDATASETATTR_QUESTION) == 0);
598 result = dns_rdataset_first(rdataset);
599 if (result != ISC_R_SUCCESS)
600 return (result);
602 do {
603 dns_rdataset_current(rdataset, &rdata);
604 result = dns_rdata_additionaldata(&rdata, add, arg);
605 if (result == ISC_R_SUCCESS)
606 result = dns_rdataset_next(rdataset);
607 dns_rdata_reset(&rdata);
608 } while (result == ISC_R_SUCCESS);
610 if (result != ISC_R_NOMORE)
611 return (result);
613 return (ISC_R_SUCCESS);
616 isc_result_t
617 dns_rdataset_addnoqname(dns_rdataset_t *rdataset, dns_name_t *name) {
619 REQUIRE(DNS_RDATASET_VALID(rdataset));
620 REQUIRE(rdataset->methods != NULL);
621 if (rdataset->methods->addnoqname == NULL)
622 return (ISC_R_NOTIMPLEMENTED);
623 return((rdataset->methods->addnoqname)(rdataset, name));
626 isc_result_t
627 dns_rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
628 dns_rdataset_t *neg, dns_rdataset_t *negsig)
630 REQUIRE(DNS_RDATASET_VALID(rdataset));
631 REQUIRE(rdataset->methods != NULL);
633 if (rdataset->methods->getnoqname == NULL)
634 return (ISC_R_NOTIMPLEMENTED);
635 return((rdataset->methods->getnoqname)(rdataset, name, neg, negsig));
638 isc_result_t
639 dns_rdataset_addclosest(dns_rdataset_t *rdataset, dns_name_t *name) {
641 REQUIRE(DNS_RDATASET_VALID(rdataset));
642 REQUIRE(rdataset->methods != NULL);
643 if (rdataset->methods->addclosest == NULL)
644 return (ISC_R_NOTIMPLEMENTED);
645 return((rdataset->methods->addclosest)(rdataset, name));
648 isc_result_t
649 dns_rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name,
650 dns_rdataset_t *neg, dns_rdataset_t *negsig)
652 REQUIRE(DNS_RDATASET_VALID(rdataset));
653 REQUIRE(rdataset->methods != NULL);
655 if (rdataset->methods->getclosest == NULL)
656 return (ISC_R_NOTIMPLEMENTED);
657 return((rdataset->methods->getclosest)(rdataset, name, neg, negsig));
661 * Additional cache stuff
663 isc_result_t
664 dns_rdataset_getadditional(dns_rdataset_t *rdataset,
665 dns_rdatasetadditional_t type,
666 dns_rdatatype_t qtype,
667 dns_acache_t *acache,
668 dns_zone_t **zonep,
669 dns_db_t **dbp,
670 dns_dbversion_t **versionp,
671 dns_dbnode_t **nodep,
672 dns_name_t *fname,
673 dns_message_t *msg,
674 isc_stdtime_t now)
676 REQUIRE(DNS_RDATASET_VALID(rdataset));
677 REQUIRE(rdataset->methods != NULL);
678 REQUIRE(zonep == NULL || *zonep == NULL);
679 REQUIRE(dbp != NULL && *dbp == NULL);
680 REQUIRE(versionp != NULL && *versionp == NULL);
681 REQUIRE(nodep != NULL && *nodep == NULL);
682 REQUIRE(fname != NULL);
683 REQUIRE(msg != NULL);
685 if (acache != NULL && rdataset->methods->getadditional != NULL) {
686 return ((rdataset->methods->getadditional)(rdataset, type,
687 qtype, acache,
688 zonep, dbp,
689 versionp, nodep,
690 fname, msg, now));
693 return (ISC_R_FAILURE);
696 isc_result_t
697 dns_rdataset_setadditional(dns_rdataset_t *rdataset,
698 dns_rdatasetadditional_t type,
699 dns_rdatatype_t qtype,
700 dns_acache_t *acache,
701 dns_zone_t *zone,
702 dns_db_t *db,
703 dns_dbversion_t *version,
704 dns_dbnode_t *node,
705 dns_name_t *fname)
707 REQUIRE(DNS_RDATASET_VALID(rdataset));
708 REQUIRE(rdataset->methods != NULL);
710 if (acache != NULL && rdataset->methods->setadditional != NULL) {
711 return ((rdataset->methods->setadditional)(rdataset, type,
712 qtype, acache, zone,
713 db, version,
714 node, fname));
717 return (ISC_R_FAILURE);
720 isc_result_t
721 dns_rdataset_putadditional(dns_acache_t *acache,
722 dns_rdataset_t *rdataset,
723 dns_rdatasetadditional_t type,
724 dns_rdatatype_t qtype)
726 REQUIRE(DNS_RDATASET_VALID(rdataset));
727 REQUIRE(rdataset->methods != NULL);
729 if (acache != NULL && rdataset->methods->putadditional != NULL) {
730 return ((rdataset->methods->putadditional)(acache, rdataset,
731 type, qtype));
734 return (ISC_R_FAILURE);