1/* $NetBSD: rriterator.c,v 1.8 2024/02/21 22:52:08 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 39isc_result_t 40dns_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 62isc_result_t 63dns_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 115isc_result_t 116dns_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 161isc_result_t 162dns_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 179void 180dns_rriterator_pause(dns_rriterator_t *it) { 181 REQUIRE(VALID_RRITERATOR(it)); 182 RUNTIME_CHECK(dns_dbiterator_pause(it->dbit) == ISC_R_SUCCESS); 183} 184 185void 186dns_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 200void 201dns_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