xref: /netbsd-src/external/mpl/bind/dist/lib/dns/rriterator.c (revision bcda20f65a8566e103791ec395f7f499ef322704)
1 /*	$NetBSD: rriterator.c,v 1.9 2025/01/26 16:25:25 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/result.h>
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/rriterator.h>
34 
35 /***
36  *** RRiterator methods
37  ***/
38 
39 isc_result_t
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
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
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
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
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
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
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 	SET_IF_NOT_NULL(rdataset, &it->rdataset);
216 
217 	SET_IF_NOT_NULL(rdata, &it->rdata);
218 }
219