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