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