xref: /netbsd-src/external/mpl/bind/dist/lib/dns/rriterator.c (revision 33881f779a77dce6440bdc44610d94de75bebefe)
1 /*	$NetBSD: rriterator.c,v 1.3 2019/01/09 16:55:12 christos Exp $	*/
2 
3 /*
4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5  *
6  * This Source Code Form is subject to the terms of the Mozilla Public
7  * License, v. 2.0. If a copy of the MPL was not distributed with this
8  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9  *
10  * See the COPYRIGHT file distributed with this work for additional
11  * information regarding copyright ownership.
12  */
13 
14 
15 /*! \file */
16 
17 /***
18  *** Imports
19  ***/
20 
21 #include <config.h>
22 
23 #include <inttypes.h>
24 
25 #include <isc/string.h>
26 #include <isc/util.h>
27 
28 #include <dns/db.h>
29 #include <dns/dbiterator.h>
30 #include <dns/rdata.h>
31 #include <dns/rdataset.h>
32 #include <dns/rdatasetiter.h>
33 #include <dns/result.h>
34 #include <dns/rriterator.h>
35 
36 /***
37  *** RRiterator methods
38  ***/
39 
40 isc_result_t
41 dns_rriterator_init(dns_rriterator_t *it, dns_db_t *db, dns_dbversion_t *ver,
42 		    isc_stdtime_t now)
43 {
44 	isc_result_t result;
45 	it->magic = RRITERATOR_MAGIC;
46 	it->db = db;
47 	it->dbit = NULL;
48 	it->ver = ver;
49 	it->now = now;
50 	it->node = NULL;
51 	result = dns_db_createiterator(it->db, 0, &it->dbit);
52 	if (result != ISC_R_SUCCESS)
53 		return (result);
54 	it->rdatasetit = NULL;
55 	dns_rdata_init(&it->rdata);
56 	dns_rdataset_init(&it->rdataset);
57 	dns_fixedname_init(&it->fixedname);
58 	INSIST(! dns_rdataset_isassociated(&it->rdataset));
59 	it->result = ISC_R_SUCCESS;
60 	return (it->result);
61 }
62 
63 isc_result_t
64 dns_rriterator_first(dns_rriterator_t *it) {
65 	REQUIRE(VALID_RRITERATOR(it));
66 	/* Reset state */
67 	if (dns_rdataset_isassociated(&it->rdataset))
68 		dns_rdataset_disassociate(&it->rdataset);
69 	if (it->rdatasetit != NULL)
70 		dns_rdatasetiter_destroy(&it->rdatasetit);
71 	if (it->node != NULL)
72 		dns_db_detachnode(it->db, &it->node);
73 	it->result = dns_dbiterator_first(it->dbit);
74 
75 	/*
76 	 * The top node may be empty when out of zone glue exists.
77 	 * Walk the tree to find the first node with data.
78 	 */
79 	while (it->result == ISC_R_SUCCESS) {
80 		it->result = dns_dbiterator_current(it->dbit, &it->node,
81 					   dns_fixedname_name(&it->fixedname));
82 		if (it->result != ISC_R_SUCCESS)
83 			return (it->result);
84 
85 		it->result = dns_db_allrdatasets(it->db, it->node, it->ver,
86 						 it->now, &it->rdatasetit);
87 		if (it->result != ISC_R_SUCCESS)
88 			return (it->result);
89 
90 		it->result = dns_rdatasetiter_first(it->rdatasetit);
91 		if (it->result != ISC_R_SUCCESS) {
92 			/*
93 			 * This node is empty. Try next node.
94 			 */
95 			dns_rdatasetiter_destroy(&it->rdatasetit);
96 			dns_db_detachnode(it->db, &it->node);
97 			it->result = dns_dbiterator_next(it->dbit);
98 			continue;
99 		}
100 		dns_rdatasetiter_current(it->rdatasetit, &it->rdataset);
101 		dns_rdataset_getownercase(&it->rdataset,
102 					  dns_fixedname_name(&it->fixedname));
103 		it->rdataset.attributes |= DNS_RDATASETATTR_LOADORDER;
104 		it->result = dns_rdataset_first(&it->rdataset);
105 		return (it->result);
106 	}
107 	return (it->result);
108 }
109 
110 isc_result_t
111 dns_rriterator_nextrrset(dns_rriterator_t *it) {
112 	REQUIRE(VALID_RRITERATOR(it));
113 	if (dns_rdataset_isassociated(&it->rdataset))
114 		dns_rdataset_disassociate(&it->rdataset);
115 	it->result = dns_rdatasetiter_next(it->rdatasetit);
116 	/*
117 	 * The while loop body is executed more than once
118 	 * only when an empty dbnode needs to be skipped.
119 	 */
120 	while (it->result == ISC_R_NOMORE) {
121 		dns_rdatasetiter_destroy(&it->rdatasetit);
122 		dns_db_detachnode(it->db, &it->node);
123 		it->result = dns_dbiterator_next(it->dbit);
124 		if (it->result == ISC_R_NOMORE) {
125 			/* We are at the end of the entire database. */
126 			return (it->result);
127 		}
128 		if (it->result != ISC_R_SUCCESS)
129 			return (it->result);
130 		it->result = dns_dbiterator_current(it->dbit, &it->node,
131 					   dns_fixedname_name(&it->fixedname));
132 		if (it->result != ISC_R_SUCCESS)
133 			return (it->result);
134 		it->result = dns_db_allrdatasets(it->db, it->node, it->ver,
135 						 it->now, &it->rdatasetit);
136 		if (it->result != ISC_R_SUCCESS)
137 			return (it->result);
138 		it->result = dns_rdatasetiter_first(it->rdatasetit);
139 	}
140 	if (it->result != ISC_R_SUCCESS)
141 		return (it->result);
142 	dns_rdatasetiter_current(it->rdatasetit, &it->rdataset);
143 	dns_rdataset_getownercase(&it->rdataset,
144 				  dns_fixedname_name(&it->fixedname));
145 	it->rdataset.attributes |= DNS_RDATASETATTR_LOADORDER;
146 	it->result = dns_rdataset_first(&it->rdataset);
147 	return (it->result);
148 }
149 
150 isc_result_t
151 dns_rriterator_next(dns_rriterator_t *it) {
152 	REQUIRE(VALID_RRITERATOR(it));
153 	if (it->result != ISC_R_SUCCESS)
154 		return (it->result);
155 
156 	INSIST(it->dbit != NULL);
157 	INSIST(it->node != NULL);
158 	INSIST(it->rdatasetit != NULL);
159 
160 	it->result = dns_rdataset_next(&it->rdataset);
161 	if (it->result == ISC_R_NOMORE)
162 		return (dns_rriterator_nextrrset(it));
163 	return (it->result);
164 }
165 
166 void
167 dns_rriterator_pause(dns_rriterator_t *it) {
168 	REQUIRE(VALID_RRITERATOR(it));
169 	RUNTIME_CHECK(dns_dbiterator_pause(it->dbit) == ISC_R_SUCCESS);
170 }
171 
172 void
173 dns_rriterator_destroy(dns_rriterator_t *it) {
174 	REQUIRE(VALID_RRITERATOR(it));
175 	if (dns_rdataset_isassociated(&it->rdataset))
176 		dns_rdataset_disassociate(&it->rdataset);
177 	if (it->rdatasetit != NULL)
178 		dns_rdatasetiter_destroy(&it->rdatasetit);
179 	if (it->node != NULL)
180 		dns_db_detachnode(it->db, &it->node);
181 	dns_dbiterator_destroy(&it->dbit);
182 }
183 
184 void
185 dns_rriterator_current(dns_rriterator_t *it, dns_name_t **name,
186 		       uint32_t *ttl, dns_rdataset_t **rdataset,
187 		       dns_rdata_t **rdata)
188 {
189 	REQUIRE(name != NULL && *name == NULL);
190 	REQUIRE(VALID_RRITERATOR(it));
191 	REQUIRE(it->result == ISC_R_SUCCESS);
192 	REQUIRE(rdataset == NULL || *rdataset == NULL);
193 	REQUIRE(rdata == NULL || *rdata == NULL);
194 
195 	*name = dns_fixedname_name(&it->fixedname);
196 	*ttl = it->rdataset.ttl;
197 
198 	dns_rdata_reset(&it->rdata);
199 	dns_rdataset_current(&it->rdataset, &it->rdata);
200 
201 	if (rdataset != NULL)
202 		*rdataset = &it->rdataset;
203 
204 	if (rdata != NULL)
205 		*rdata = &it->rdata;
206 }
207