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