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