Home | History | Annotate | Line # | Download | only in dns
      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