From a7e185ff3f7db73e282bf53b9f84a95ff8f8cb27 Mon Sep 17 00:00:00 2001 From: Bob Halley Date: Wed, 16 Jun 1999 21:02:17 +0000 Subject: [PATCH] Add dns_db_subtractrdataset(). Add DNS_R_UNCHANGED results for dns_db_{add,delete}rdataset(). Add merge flag to dns_db_addrdataset(). The way add and delete work should now match the .h file comments. --- lib/dns/db.c | 31 +++++++++++++++-- lib/dns/include/dns/db.h | 61 ++++++++++++++++++++++++++++++--- lib/dns/rbtdb.c | 73 +++++++++++++++++++++++++++++++++------- 3 files changed, 145 insertions(+), 20 deletions(-) diff --git a/lib/dns/db.c b/lib/dns/db.c index 10baf97cf9..a1a0c29fe6 100644 --- a/lib/dns/db.c +++ b/lib/dns/db.c @@ -420,7 +420,7 @@ dns_db_allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, dns_result_t dns_db_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, isc_stdtime_t now, dns_rdataset_t *rdataset, - dns_rdataset_t *addedrdataset) + isc_boolean_t merge, dns_rdataset_t *addedrdataset) { /* * Add 'rdataset' to 'node' in version 'version' of 'db'. @@ -429,7 +429,8 @@ dns_db_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, REQUIRE(DNS_DB_VALID(db)); REQUIRE(node != NULL); REQUIRE(((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL)|| - ((db->attributes & DNS_DBATTR_CACHE) != 0 && version == NULL)); + ((db->attributes & DNS_DBATTR_CACHE) != 0 && + version == NULL && !merge)); REQUIRE(DNS_RDATASET_VALID(rdataset)); REQUIRE(rdataset->methods != NULL); REQUIRE(rdataset->rdclass == db->rdclass); @@ -438,7 +439,31 @@ dns_db_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, addedrdataset->methods == NULL)); return ((db->methods->addrdataset)(db, node, version, now, rdataset, - addedrdataset)); + merge, addedrdataset)); +} + +dns_result_t +dns_db_subtractrdataset(dns_db_t *db, dns_dbnode_t *node, + dns_dbversion_t *version, dns_rdataset_t *rdataset, + dns_rdataset_t *newrdataset) +{ + /* + * Remove any rdata in 'rdataset' from 'node' in version 'version' of + * 'db'. + */ + + REQUIRE(DNS_DB_VALID(db)); + REQUIRE(node != NULL); + REQUIRE(((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL)); + REQUIRE(DNS_RDATASET_VALID(rdataset)); + REQUIRE(rdataset->methods != NULL); + REQUIRE(rdataset->rdclass == db->rdclass); + REQUIRE(newrdataset == NULL || + (DNS_RDATASET_VALID(newrdataset) && + newrdataset->methods == NULL)); + + return ((db->methods->subtractrdataset)(db, node, version, rdataset, + newrdataset)); } dns_result_t diff --git a/lib/dns/include/dns/db.h b/lib/dns/include/dns/db.h index 1dc29ec8e9..f16f82bb71 100644 --- a/lib/dns/include/dns/db.h +++ b/lib/dns/include/dns/db.h @@ -119,7 +119,12 @@ typedef struct dns_dbmethods { dns_dbversion_t *version, isc_stdtime_t now, dns_rdataset_t *rdataset, + isc_boolean_t merge, dns_rdataset_t *addedrdataset); + dns_result_t (*subtractrdataset)(dns_db_t *db, dns_dbnode_t *node, + dns_dbversion_t *version, + dns_rdataset_t *rdataset, + dns_rdataset_t *newrdataset); dns_result_t (*deleterdataset)(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, dns_rdatatype_t type); @@ -794,12 +799,18 @@ dns_db_allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, dns_result_t dns_db_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, isc_stdtime_t now, dns_rdataset_t *rdataset, - dns_rdataset_t *addedrdataset); + isc_boolean_t merge, dns_rdataset_t *addedrdataset); /* * Add 'rdataset' to 'node' in version 'version' of 'db'. * * Notes: * + * If the database has zone semantics, 'merge' is ISC_TRUE, and an + * rdataset of the same type as 'rdataset' already exists at 'node', + * then the contents of 'rdataset' will be merged with the existing + * rdataset. If merge is ISC_FALSE, then rdataset will replace any + * existing rdataset of the same type. + * * The 'now' field is ignored if 'db' is a zone database. If 'db' is * a cache database, then the added rdataset will expire no later than * now + rdataset->ttl. @@ -822,13 +833,52 @@ dns_db_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, * read-write version, or the database has cache semantics * and version is NULL. * + * If the database has cache semantics, 'merge' must be ISC_FALSE. + * * Returns: * * DNS_R_SUCCESS + * DNS_R_UNCHANGED The operation did not change anything. * DNS_R_NOMEMORY - * DNS_R_EXISTS An rdataset with the specified - * rdataset's type and version's serial - * number already exists. + * + * Other results are possible, depending upon the database + * implementation used. + */ + +dns_result_t +dns_db_subtractrdataset(dns_db_t *db, dns_dbnode_t *node, + dns_dbversion_t *version, dns_rdataset_t *rdataset, + dns_rdataset_t *newrdataset); +/* + * Remove any rdata in 'rdataset' from 'node' in version 'version' of + * 'db'. + * + * Notes: + * + * If 'newrdataset' is not NULL, then it will be attached to the + * rdataset added to the database, unless the rdataset has become + * nonexistent. + * + * Requires: + * + * 'db' is a valid database. + * + * 'node' is a valid node. + * + * 'rdataset' is a valid, associated rdataset with the same class + * as 'db'. + * + * 'newrdataset' is NULL, or a valid, unassociated rdataset. + * + * The database has zone semantics and 'version' is a valid + * read-write version. + * + * Returns: + * + * DNS_R_SUCCESS + * DNS_R_UNCHANGED The operation did not change anything. + * DNS_R_NXRDATASET All rdata of the same type as those + * in 'rdataset' have been deleted. * * Other results are possible, depending upon the database * implementation used. @@ -867,7 +917,8 @@ dns_db_deleterdataset(dns_db_t *db, dns_dbnode_t *node, * Returns: * * DNS_R_SUCCESS - * DNS_R_NOTFOUND + * DNS_R_UNCHANGED No rdatasets of 'type' existed before + * the operation was attempted. * * Other results are possible, depending upon the database * implementation used. diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index eda0e2699c..ea463dfd7b 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -2274,6 +2274,9 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, rdatasetheader_t *header, *header_prev; unsigned char *merged; dns_result_t result; + isc_boolean_t force = ISC_FALSE; + isc_boolean_t header_nx; + isc_boolean_t newheader_nx; /* * Add an rdatasetheader_t to a node. @@ -2284,11 +2287,19 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, */ if (rbtversion != NULL && !loading) { + /* + * We always add a changed record, even if no changes end up + * being made to this node, because it's harmless and + * simplifies the code. + */ changed = add_changed(rbtdb, rbtversion, rbtnode); if (changed == NULL) return (DNS_R_NOMEMORY); } + newheader_nx = ((newheader->attributes & RDATASET_ATTR_NONEXISTENT) + != 0 ? ISC_TRUE : ISC_FALSE); + header_prev = NULL; for (header = rbtnode->data; header != NULL; header = header->next) { if (header->type == newheader->type) @@ -2296,13 +2307,28 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, header_prev = header; } if (header != NULL) { + header_nx = ((header->attributes & RDATASET_ATTR_NONEXISTENT) + != 0 ? ISC_TRUE : ISC_FALSE); + + /* + * Deleting an already non-existent rdataset has no effect. + */ + if (header_nx && newheader_nx) { + free_rdataset(rbtdb->common.mctx, newheader); + return (DNS_R_UNCHANGED); + } + /* * Don't merge if a nonexistent rdataset is involved. */ - if (merge && - ((newheader->attributes & RDATASET_ATTR_NONEXISTENT) != 0 - || (header->attributes & RDATASET_ATTR_NONEXISTENT) != 0)) + if (merge && (header_nx || newheader_nx)) merge = ISC_FALSE; + + /* + * XXXRTH We should turn off merging for rdata types that + * cannot be merged, e.g. SOA, CNAME, WKS. + */ + /* * If 'merge' is ISC_TRUE, we'll try to create a new rdataset * that is the union of 'newheader' and 'header'. @@ -2310,6 +2336,12 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, if (merge) { INSIST(rbtversion->serial >= header->serial); merged = NULL; + if (newheader->ttl != header->ttl) + force = ISC_TRUE; + /* + * XXXRTH we're going to have to deal with signatures + * somehow here... + */ result = dns_rdataslab_merge( (unsigned char *)header, (unsigned char *)newheader, @@ -2317,6 +2349,7 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, rbtdb->common.mctx, rbtdb->common.rdclass, header->type, + force, &merged); if (result == DNS_R_SUCCESS) { /* @@ -2331,13 +2364,6 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, newheader = (rdatasetheader_t *)merged; } else { free_rdataset(rbtdb->common.mctx, newheader); - if (result == DNS_R_UNCHANGED) { - if (addedrdataset != NULL) - bind_rdataset(rbtdb, rbtnode, - header, now, - addedrdataset); - return (DNS_R_SUCCESS); - } return (result); } } @@ -2368,6 +2394,15 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, /* * The rdataset type doesn't exist at this node. */ + + /* + * If we're trying to delete it, don't bother. + */ + if (newheader_nx) { + free_rdataset(rbtdb->common.mctx, newheader); + return (DNS_R_UNCHANGED); + } + newheader->next = rbtnode->data; newheader->down = NULL; rbtnode->data = newheader; @@ -2394,7 +2429,7 @@ delegating_type(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, static dns_result_t addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, - isc_stdtime_t now, dns_rdataset_t *rdataset, + isc_stdtime_t now, dns_rdataset_t *rdataset, isc_boolean_t merge, dns_rdataset_t *addedrdataset) { dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; @@ -2403,7 +2438,7 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, isc_region_t region; rdatasetheader_t *newheader; dns_result_t result; - isc_boolean_t merge, delegating; + isc_boolean_t delegating; REQUIRE(VALID_RBTDB(rbtdb)); @@ -2459,6 +2494,18 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, return (result); } +static dns_result_t +subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, + dns_rdataset_t *rdataset, dns_rdataset_t *newrdataset) { + (void)db; + (void)node; + (void)version; + (void)rdataset; + (void)newrdataset; + + return (DNS_R_NOTIMPLEMENTED); +} + static dns_result_t deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, dns_rdatatype_t type) @@ -2659,6 +2706,7 @@ static dns_dbmethods_t zone_methods = { zone_findrdataset, allrdatasets, addrdataset, + subtractrdataset, deleterdataset }; @@ -2681,6 +2729,7 @@ static dns_dbmethods_t cache_methods = { cache_findrdataset, allrdatasets, addrdataset, + subtractrdataset, deleterdataset };