BIND 10 trac1198, updated. b8e895092634bc661baf7fa043fffdba511f8256 [1198] Checkpoint after updating internal documentation

BIND 10 source code commits bind10-changes at lists.isc.org
Fri Nov 25 19:24:09 UTC 2011


The branch, trac1198 has been updated
       via  b8e895092634bc661baf7fa043fffdba511f8256 (commit)
       via  1bad76a6ab0ece059d8a587870f1da84510eccc5 (commit)
      from  b4471621912e7518088b106d829a8431a6c4ea97 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit b8e895092634bc661baf7fa043fffdba511f8256
Author: Stephen Morris <stephen at isc.org>
Date:   Fri Nov 25 19:23:28 2011 +0000

    [1198] Checkpoint after updating internal documentation

commit 1bad76a6ab0ece059d8a587870f1da84510eccc5
Author: Stephen Morris <stephen at isc.org>
Date:   Fri Nov 25 16:43:41 2011 +0000

    [1198] Add reordered message file and utility to do this
    
    Added utility to put messages in a message file into alphabetical
    order and, for ease of further editing, the data source message file
    in alphabetical order.

-----------------------------------------------------------------------

Summary of changes:
 src/lib/datasrc/database.cc          |  185 +++++++++++++++++----------
 src/lib/datasrc/database.h           |  233 ++++++++++++++++++++--------------
 src/lib/datasrc/datasrc_messages.mes |  103 ++++++++-------
 tools/reorder_message_file.py        |  196 ++++++++++++++++++++++++++++
 4 files changed, 507 insertions(+), 210 deletions(-)
 create mode 100644 tools/reorder_message_file.py

-----------------------------------------------------------------------
diff --git a/src/lib/datasrc/database.cc b/src/lib/datasrc/database.cc
index 478a689..d5baebf 100644
--- a/src/lib/datasrc/database.cc
+++ b/src/lib/datasrc/database.cc
@@ -392,8 +392,7 @@ DatabaseClient::Finder::findNSECCover(const Name& name) {
 
 DatabaseClient::Finder::DelegationSearchResult
 DatabaseClient::Finder::findDelegationPoint(const isc::dns::Name& name,
-                                            const FindOptions options)
-{
+                                            const FindOptions options) {
     // Result of search
     isc::dns::ConstRRsetPtr result_rrset;
     ZoneFinder::Result result_status = SUCCESS;
@@ -405,53 +404,60 @@ DatabaseClient::Finder::findDelegationPoint(const isc::dns::Name& name,
     // Are we searching for glue?
     const bool glue_ok((options & FIND_GLUE_OK) != 0);
 
-    // First, do we have any kind of delegation (NS/DNAME) here?
-    const Name origin(getOrigin());
-    const size_t origin_label_count(origin.getLabelCount());
-
-    // Number of labels in the last known non-empty domain
-    size_t last_known(origin_label_count);
-    const size_t current_label_count(name.getLabelCount());
+    // We want to search from the apex down.  We are given the full domain
+    // name so we have to do some manipulation to ensure that when we start
+    // checking superdomains, we start from the right label:
+    //
+    // Set the number of labels in the origin (i.e. apex of the zone) and in
+    // the last known non-empty domain (which, at this point, is the origin).
+    const size_t origin_label_count = getOrigin().getLabelCount();
+    size_t last_known = origin_label_count;
 
-    // This is how many labels we remove to get origin
-    const size_t remove_labels(current_label_count - origin_label_count);
+    // Set how many labels we remove to get origin: this is the number of
+    // labels we have to process in our search.
+    const size_t remove_labels = name.getLabelCount() - origin_label_count;
 
     // Go through all superdomains from the origin down searching for nodes
     // that indicate a delegation (NS or DNAME).
     for (int i = remove_labels; i > 0; --i) {
         const Name superdomain(name.split(i));
 
-        // Note if this is the origin.
+        // Note if this is the origin. (We don't count NS records at the origin
+        // as a delegation so this controls whether NS RRs are included in
+        // the results of some searches.)
         const bool not_origin = (i != remove_labels);
 
-        // Look if there's NS or DNAME (but ignore the NS in origin)
+        // Look if there's NS or DNAME at this point of the tree, but ignore the
+        // NS RRs at the apex of the zone.
         const FoundRRsets found = getRRsets(superdomain.toText(),
                                             DELEGATION_TYPES(), not_origin);
         if (found.first) {
-            // It contains some RRs, so it exists.
+            // This node contains either NS or DNAME RRs so it does exist.
             last_known = superdomain.getLabelCount();
-
             const FoundIterator nsi(found.second.find(RRType::NS()));
             const FoundIterator dni(found.second.find(RRType::DNAME()));
 
             // In case we are in GLUE_OK mode, we want to store the
             // highest encountered NS (but not apex)
-            if (glue_ok && !first_ns && not_origin && nsi != found.second.end()) {
+            // TODO: WHY?
+            if (glue_ok && !first_ns && not_origin &&
+                    nsi != found.second.end()) {
                 first_ns = nsi->second;
 
             } else if (!glue_ok && not_origin && nsi != found.second.end()) {
-                // Do a NS delegation, but ignore NS in glue_ok mode. Ignore
-                // delegation in apex
+                // Not in glue OK mode and we have found an NS RRset that is
+                // not at the apex.  We have a delegation so return that fact.
                 LOG_DEBUG(logger, DBG_TRACE_DETAILED,
                           DATASRC_DATABASE_FOUND_DELEGATION).
                     arg(accessor_->getDBName()).arg(superdomain);
                 result_rrset = nsi->second;
                 result_status = DELEGATION;
-                // No need to go lower, found
+
+                // No need to go further down the tree.
                 break;
 
             } else if (dni != found.second.end()) {
-                // Very similar with DNAME
+                // We have found a DNAME so again return the fact.
                 LOG_DEBUG(logger, DBG_TRACE_DETAILED,
                           DATASRC_DATABASE_FOUND_DNAME).
                     arg(accessor_->getDBName()).arg(superdomain);
@@ -462,6 +468,8 @@ DatabaseClient::Finder::findDelegationPoint(const isc::dns::Name& name,
                               " has " << result_rrset->getRdataCount() <<
                               " rdata, 1 expected");
                 }
+
+                // No need to go further down the tree.
                 break;
             }
         }
@@ -475,14 +483,17 @@ DatabaseClient::Finder::findWildcardMatch(
     const isc::dns::Name& name, const isc::dns::RRType& type,
     const FindOptions options, const DelegationSearchResult& dresult)
 {
-    // Result of search
+    // Result of search (status initialized to assume we don't find any
+    // matching RRsets).
     isc::dns::ConstRRsetPtr result_rrset;
-    ZoneFinder::Result result_status = NXDOMAIN; // in case we don't find any
+    ZoneFinder::Result result_status = NXDOMAIN;
 
     // Search options
     const bool dnssec_data((options & FIND_DNSSEC) != 0);
 
-    // Other
+    // Note that during the search we are going to search not only for the
+    // requested type, but also for types that indicate a delegation -
+    // NS and DNAME.
     WantedTypes final_types(FINAL_TYPES());
     final_types.insert(type);
 
@@ -583,33 +594,40 @@ DatabaseClient::Finder::findNoNameResult(const Name& name, const RRType& type,
                                          FindOptions options,
                                          const DelegationSearchResult& dresult)
 {
-    const bool dnssec_data((options & FIND_DNSSEC) != 0);
+    const bool dnssec_data = ((options & FIND_DNSSEC) != 0);
+
+    // On entry to this method, we know that the database doesn't have any
+    // entry for this name.  Before returning NXDOMAIN, we need to check
+    // for special cases.
 
-    // We know the database doesn't have any record for the given name.
-    // But check if something lives below this domain and if so,
-    // pretend something is here as well.
     if (hasSubdomains(name.toText())) {
+        // Does the domain have a subdomain (i.e. is is an empty non-terminal)?
+        // If so, return NXRRSET instead of NXDOMAIN (as although the name does
+        // not exist in the zone, it does exist in the DNS tree).
+        // pretend something is here as well.
         LOG_DEBUG(logger, DBG_TRACE_DETAILED,
                   DATASRC_DATABASE_FOUND_EMPTY_NONTERMINAL).
             arg(accessor_->getDBName()).arg(name);
         return (FindResult(NXRRSET, dnssec_data ? findNSECCover(name) :
                            ConstRRsetPtr()));
-    } else if ((options & NO_WILDCARD) != 0) {
-        // If wildcard check is disabled, the search should terminate
-        // with NXDOMAIN.
-        return (FindResult(NXDOMAIN, dnssec_data ? findNSECCover(name) :
-                           ConstRRsetPtr()));
-    } else {
-        // It's not an empty non-terminal so check for wildcards.
+
+    } else if ((options & NO_WILDCARD) == 0) {
+        // It's not an empty non-terminal and wildcard matching is not disabled,
+        // so check for wildcards.
         const ZoneFinder::FindResult wresult =
             findWildcardMatch(name, type, options, dresult);
         if (wresult.code == NXDOMAIN && dnssec_data) {
-            // If the result is NXDOMAIN case and the caller wanted
-            // DNSSEC data, try getting the NSEC record.
+            // No match on a wildcard, so return the covering NSEC if DNSSEC
+            // data was requested.
             return (FindResult(NXDOMAIN, findNSECCover(name)));
         }
         return (FindResult(wresult.code, wresult.rrset));
     }
+
+    // All avenues to find a match are now exhausted, return NXDOMAIN (plus
+    // NSEC records if requested).
+    return (FindResult(NXDOMAIN, dnssec_data ? findNSECCover(name) :
+                           ConstRRsetPtr()));
 }
 
 ZoneFinder::FindResult
@@ -621,8 +639,8 @@ DatabaseClient::Finder::logAndCreateResult(const Name& name,
 {
     if (rrset) {
         LOG_DEBUG(logger, DBG_TRACE_DETAILED, log_id).
-            arg(accessor_->getDBName()).arg(name).arg(getClass()).
-            arg(type).arg(*rrset);
+            arg(accessor_->getDBName()).arg(name).arg(type).arg(getClass()).
+            arg(*rrset);
     } else {
         LOG_DEBUG(logger, DBG_TRACE_DETAILED, log_id).
             arg(accessor_->getDBName()).arg(name).arg(type).arg(getClass());
@@ -634,61 +652,98 @@ ZoneFinder::FindResult
 DatabaseClient::Finder::find(const isc::dns::Name& name,
                              const isc::dns::RRType& type,
                              isc::dns::RRsetList*,
-                             const FindOptions options)
-{
+                             const FindOptions options) {
     LOG_DEBUG(logger, DBG_TRACE_DETAILED, DATASRC_DATABASE_FIND_RECORDS)
               .arg(accessor_->getDBName()).arg(name).arg(type);
 
-    // First stage: go through all superdomains from the origin down,
-    // searching for nodes that indicate a delegation (NS or DNAME).
+    // First, go through all superdomains from the origin down, searching for
+    // nodes that indicate a delegation (i.e. NS or DNAME, ignoring NS records
+    // at the apex).  If one is found, the search stops there.
+    //
+    // (In fact there could be RRs in the database corresponding to subdomains
+    // of the delegation.  However as no search will find them, they are said
+    // to be occluded by the presence of the delegation.)
     const DelegationSearchResult dresult = findDelegationPoint(name, options);
     if (dresult.rrset) {
         return (FindResult(dresult.code, dresult.rrset));
     }
 
-    // Try getting the final result and extract it
-    // It is special if there's a CNAME or NS, DNAME is ignored here
-    // And we don't consider the NS in origin
+    // If there is no delegation in the page, look for the exact match to the
+    // request name/type/class.  However, there are special cases:
+    // - Requested name has a singleton CNAME record associated with it
+    // - Requested name is a delegation point (NS only but not at the zone
+    //   apex - DNAME is ignored here).
+    // TODO: Why is DNAME ignored?
     const bool is_origin = (name == getOrigin());
     WantedTypes final_types(FINAL_TYPES());
     final_types.insert(type);
-    const FoundRRsets found(getRRsets(name.toText(), final_types, !is_origin));
+    const FoundRRsets found = getRRsets(name.toText(), final_types, !is_origin);
 
-    // NS records, CNAME record and Wanted Type records
+    // Get iterators for the different types of records we are interested in -
+    // CNAME, NS and Wanted types.
     const FoundIterator nsi(found.second.find(RRType::NS()));
     const FoundIterator cni(found.second.find(RRType::CNAME()));
     const FoundIterator wti(found.second.find(type));
 
-    if (!is_origin && (options & FIND_GLUE_OK) == 0 &&
-        nsi != found.second.end()) { // delegation at the exact node
+    if (!is_origin && ((options & FIND_GLUE_OK) == 0) &&
+            nsi != found.second.end()) { 
+        // A NS RRset was found at the domain we were searching for.  As
+        // it is not at the origin of the zone, it is a delegation and
+        // indicates that this this zone is not authoritative for the data.
+        // Just return the delegation information.
         return (logAndCreateResult(name, type, DELEGATION, nsi->second,
                                    DATASRC_DATABASE_FOUND_DELEGATION_EXACT));
-    } else if (type != RRType::CNAME() && cni != found.second.end()) { // CNAME
+
+    } else if (type != RRType::CNAME() && cni != found.second.end()) {
+        // We are not searching for a CNAME but nevertheless we have found one
+        // at the name we are searching so we return it. (A resolver could have
+        // originated the query that caues this result.  If so, it will restart
+        // the resolution process with the name that is the target of this
+        // CNAME.) First though, do a sanity check to ensure that there is
+        // only one RR in the CNAME RRset.
+        //
+        // TODO: Check that throwing an exception here is correct.
+        // Unless the exception is caught higher up (probably not, given the
+        // general nature of the exception), it is probably better to log
+        // and error and terminate the query with SERVFAIL instead of crashing
+        // the server.  Although the CNAME is a singleton and multiple RRs
+        // in the RRset may indicate an error in the data, it does not mean
+        // that the entire database is corrupt.
         if (cni->second->getRdataCount() != 1) {
             isc_throw(DataSourceError, "CNAME with " <<
-                      cni->second->getRdataCount() <<
-                      " rdata at " << name << ", expected 1");
+                      cni->second->getRdataCount() << " rdata at " << name <<
+                      ", expected 1");
         }
         return (logAndCreateResult(name, type, CNAME, cni->second,
                                    DATASRC_DATABASE_FOUND_CNAME));
-    } else if (wti != found.second.end()) { // normal answer
+
+    } else if (wti != found.second.end()) {
+        // Found an RR matching the query, so return it.  (Note that this
+        // includes the case where we were querying for a CNAME and found
+        // it.  It also includes the case where we were querying for an NS
+        // RRset and found it at the apex of the zone.)
         return (logAndCreateResult(name, type, SUCCESS, wti->second,
                                    DATASRC_DATABASE_FOUND_RRSET));
-    } else if (!found.first) { // NXDOMAIN, empty name, wildcard
+
+    } else if (!found.first) {
+        // Did not find anything at all at the domain name, so check for
+        // subdomains or wildcards.
         return (findNoNameResult(name, type, options, dresult));
-    } else {
-        // This is the "usual" NXRRSET case.  So in case they want DNSSEC,
-        // provide the NSEC (which should be available already here)
-        if ((options & FIND_DNSSEC) != 0) {
-            const FoundIterator nci(found.second.find(RRType::NSEC()));
-            if (nci != found.second.end()) {
-                return (logAndCreateResult(name, type, NXRRSET, nci->second,
-                                           DATASRC_DATABASE_FOUND_NXRRSET_NSEC));
-            }
+
+    }
+
+    // If we get here, we have found something at the requested name but not
+    // one of the RR types we were interested in. This is the NXRRSET case so,
+    // if DNSSEC information was requested, provide the NSEC records.
+    if ((options & FIND_DNSSEC) != 0) {
+        const FoundIterator nci = found.second.find(RRType::NSEC());
+        if (nci != found.second.end()) {
+            return (logAndCreateResult(name, type, NXRRSET, nci->second,
+                                       DATASRC_DATABASE_FOUND_NXRRSET_NSEC));
         }
-        return (logAndCreateResult(name, type, NXRRSET, ConstRRsetPtr(),
-                                   DATASRC_DATABASE_FOUND_NXRRSET));
     }
+    return (logAndCreateResult(name, type, NXRRSET, ConstRRsetPtr(),
+                                   DATASRC_DATABASE_FOUND_NXRRSET));
 }
 
 Name
diff --git a/src/lib/datasrc/database.h b/src/lib/datasrc/database.h
index 3e9a8b8..bd07481 100644
--- a/src/lib/datasrc/database.h
+++ b/src/lib/datasrc/database.h
@@ -817,6 +817,17 @@ public:
             return (*accessor_);
         }
 
+    private:
+        boost::shared_ptr<DatabaseAccessor> accessor_;
+        const int zone_id_;
+        const isc::dns::Name origin_;
+        //
+        /// \brief Shortcut name for the result of getRRsets
+        typedef std::pair<bool, std::map<dns::RRType, dns::RRsetPtr> >
+            FoundRRsets;
+        /// \brief Just shortcut for set of types
+        typedef std::set<dns::RRType> WantedTypes;
+
         /// \brief Search result of \c findDelegationPoint().
         ///
         /// This is a tuple combining the result of the search - a status code
@@ -850,17 +861,6 @@ public:
             const size_t last_known; ///< No. labels in last non-empty domain
         };
 
-    private:
-        boost::shared_ptr<DatabaseAccessor> accessor_;
-        const int zone_id_;
-        const isc::dns::Name origin_;
-        //
-        /// \brief Shortcut name for the result of getRRsets
-        typedef std::pair<bool, std::map<dns::RRType, dns::RRsetPtr> >
-            FoundRRsets;
-        /// \brief Just shortcut for set of types
-        typedef std::set<dns::RRType> WantedTypes;
-
         /**
          * \brief Searches database for RRsets of one domain.
          *
@@ -892,112 +892,151 @@ public:
                               const WantedTypes& types, bool check_ns,
                               const std::string* construct_name = NULL);
 
-        /**
-         * \brief Find delegation point
-         *
-         * Given a name, searches through the superdomains from the origin
-         * down, searching for a point that indicates a delegation (i.e. an
-         * NS record or a DNAME).
-         *
-         * The method operates in two modes, non-glue-ok and glue-ok modes:
-         *
-         * In non-glue-ok mode, the search is made purely for the NS or DNAME
-         * RR.  The zone is searched from the origin down looking  for one
-         * of these RRTypes (and ignoring the NS records at the zone origin).
-         * A status is returned indicating what is found: DNAME, DELEGATION
-         * of SUCCESS, the last indicating that nothing was found, together
-         * with a pointer to the relevant RR.
-         *
-         * In glue-ok mode, the first NS encountered in the search (apart from
-         * the NS at the zone apex) is remembered but otherwise NS records are
-         * ignored and the search attempts to find a DNAME.  The result is
-         * returned in the same format, along with a pointer to the first non-
-         * apex NS (if found).
-         *
-         * \param name The name to find
-         * \param options Options about how to search. See the documentation for
-         *        ZoneFinder::FindOptions.
-         *
-         * \return Tuple holding the result of the search - the RRset of the
-         *         delegation point and the type of the point (DELEGATION or
-         *         DNAME) - and associated information.  This latter item
-         *         comprises two pieces of data: a pointer to the highest
-         *         encountered NS, and the number of labels in the last known
-         *         non-empty domain.  The associated information is found as
-         *         a natural part of the search for the delegation point and
-         *         is used later in the find() processing; it is passed back
-         *         to avoid the need to perform a second search to obtain it.
-         */
+        /// \brief Find delegation point
+        ///
+        /// Given a name, searches through the superdomains from the origin
+        /// down, searching for a point that indicates a delegation (i.e. an
+        /// NS record or a DNAME).
+        ///
+        /// The method operates in two modes, non-glue-ok and glue-ok modes:
+        ///
+        /// In non-glue-ok mode, the search is made purely for the NS or DNAME
+        /// RR.  The zone is searched from the origin down looking  for one
+        /// of these RRTypes (and ignoring the NS records at the zone origin).
+        /// A status is returned indicating what is found: DNAME, DELEGATION
+        /// of SUCCESS, the last indicating that nothing was found, together
+        /// with a pointer to the relevant RR.
+        ///
+        /// In glue-ok mode, the first NS encountered in the search (apart from
+        /// the NS at the zone apex) is remembered but otherwise NS records are
+        /// ignored and the search attempts to find a DNAME.  The result is
+        /// returned in the same format, along with a pointer to the first non-
+        /// apex NS (if found).
+        ///
+        /// \param name The name to find
+        /// \param options Options about how to search. See the documentation
+        ///        for ZoneFinder::FindOptions.
+        ///
+        /// \return Tuple holding the result of the search - the RRset of the
+        ///         delegation point and the type of the point (DELEGATION or
+        ///         DNAME) - and associated information.  This latter item
+        ///         comprises two pieces of data: a pointer to the highest
+        ///         encountered NS, and the number of labels in the last known
+        ///         non-empty domain.  The associated information is found as
+        ///         a natural part of the search for the delegation point and
+        ///         is used later in the find() processing; it is passed back
+        ///         to avoid the need to perform a second search to obtain it.
         DelegationSearchResult
         findDelegationPoint(const isc::dns::Name& name,
                             const FindOptions options);
 
-        /**
-         * \brief Find wildcard match
-         *
-         * Having found that the name is not an empty non-terminal, this
-         * searches the zone for for wildcards that match the name.
-         *
-         * It searches superdomains of the name from the zone origin down
-         * looking for a wildcard in the zone that matches the name.  There
-         * are several cases to consider:
-         *
-         * - If the previous search for a delegation point has found that
-         *   there is an NS at the superdomain of the point at which the
-         *   wildcard is found, the delegation is returned.
-         * - If there is a match to the name, an appropriate status is
-         *   returned (match on requested type, delegation, cname, or just
-         *   the indication of a match but no RRs relevant to the query).
-         * - If the match is to an non-empty non-terminal wildcard, a
-         *   wildcard NXRRSET is returned.
-         *
-         * Note that if DNSSEC is enabled for the search and the zone uses
-         * NSEC for authenticated denial of existence, the search may
-         * return NSEC records.
-         *
-         * \param name The name to find
-         * \param type The RRType to find
-         * \param options Options about how to search. See the documentation
-         *        for ZoneFinder::FindOptions.
-         * \param first_ns A pointer to the first NS found in a search for
-         *        the name (will only be non-null in glue-ok mode).
-         * \param last_known the number of labels in the last known non-empty
-         *        domain in the name.
-         *
-         * \return Tuple holding the result of the search - the RRset of the
-         *         wildcard records matching the name, together with a status
-         *         indicating the match type (e.g. CNAME at the wildcard
-         *         match, no RRs of the requested type at the wildcard,
-         *         success due to an exact match).  Also returned if there
-         *         is no match is an indication as to whether there was an
-         *         NXDOMAIN or an NXRRSET.
-         */
+        /// \brief Find wildcard match
+        /// 
+        /// Having found that the name is not an empty non-terminal, this
+        /// searches the zone for for wildcards that match the name.
+        /// 
+        /// It searches superdomains of the name from the zone origin down
+        /// looking for a wildcard in the zone that matches the name.  There
+        /// are several cases to consider:
+        /// 
+        /// - If the previous search for a delegation point has found that
+        ///   there is an NS at the superdomain of the point at which the
+        ///   wildcard is found, the delegation is returned.
+        /// - If there is a match to the name, an appropriate status is
+        ///   returned (match on requested type, delegation, cname, or just
+        ///   the indication of a match but no RRs relevant to the query).
+        /// - If the match is to an non-empty non-terminal wildcard, a
+        ///   wildcard NXRRSET is returned.
+        /// 
+        /// Note that if DNSSEC is enabled for the search and the zone uses
+        /// NSEC for authenticated denial of existence, the search may
+        /// return NSEC records.
+        /// 
+        /// \param name The name to find
+        /// \param type The RRType to find
+        /// \param options Options about how to search. See the documentation
+        ///        for ZoneFinder::FindOptions.
+        /// \param dresult Result of the search through the zone for a
+        ///        delegation.
+        /// 
+        /// \return Tuple holding the result of the search - the RRset of the
+        ///         wildcard records matching the name, together with a status
+        ///         indicating the match type (e.g. CNAME at the wildcard
+        ///         match, no RRs of the requested type at the wildcard,
+        ///         success due to an exact match).  Also returned if there
+        ///         is no match is an indication as to whether there was an
+        ///         NXDOMAIN or an NXRRSET.
         FindResult findWildcardMatch(
             const isc::dns::Name& name,
             const isc::dns::RRType& type, const FindOptions options,
             const DelegationSearchResult& dresult);
 
-        /// To be documented.
+        /// \brief Handle no match for name
+        ///
+        /// This is called when it is known that there is no delegation and
+        /// there is no exact match for the name (regardless of RR types
+        /// requested).  Before returning NXDOMAIN, we need to check two
+        /// cases:
+        /// - Empty non-terminal: if the name has subdomains in the database,
+        ///   flag the fact.  An NXRRSET will be returned (along with the
+        ///   NSEC record covering the requested domain name if DNSSEC data
+        ///   is being returned).
+        /// - Wildcard: is there a wildcard record in the zone that matches
+        ///   requested name? If so, return it.  If not, return the relevant
+        ///   NSEC records (if requested).
+        /// 
+        /// \param name The name to find
+        /// \param type The RRType to find
+        /// \param options Options about how to search. See the documentation
+        ///        for ZoneFinder::FindOptions.
+        /// \param dresult Result of the search through the zone for a
+        ///        delegation.
+        /// 
+        /// \return Tuple holding the result of the search - the RRset of the
+        ///         wildcard records matching the name, together with a status
+        ///         indicating the match type (e.g. CNAME at the wildcard
+        ///         match, no RRs of the requested type at the wildcard,
+        ///         success due to an exact match).  Also returned if there
+        ///         is no match is an indication as to whether there was an
+        ///         NXDOMAIN or an NXRRSET.
         FindResult findNoNameResult(const isc::dns::Name& name,
                                     const isc::dns::RRType& type,
                                     FindOptions options,
                                     const DelegationSearchResult& dresult);
 
-        // To be documented.
+        /// Logs condition and creates result
+        ///
+        /// A convenience function used by find(), it both creates the
+        /// FindResult object that find() will return to its caller as well
+        /// as logging a debug message for the information being returned.
+        ///
+        /// \param name Domain name of the RR that was being sought.
+        /// \param type Type of RR being sought.
+        /// \param code Result of the find operation
+        /// \param rrset RRset found as a result of the find (which may be
+        ///        null).
+        /// \param log_id ID of the message being logged.  Up to five
+        ///        parameters are available to the message: data source name,
+        ///        requested domain name, requested class, requested type
+        ///        and (but only if the search was successful and returned
+        ///        an RRset) details of the RRset found.
+        ///
+        /// \return FindResult object constructed from the code and rrset
+        ///         arguments.
         FindResult logAndCreateResult(const isc::dns::Name& name,
                                       const isc::dns::RRType& type,
                                       ZoneFinder::Result code,
                                       isc::dns::ConstRRsetPtr rrset,
                                       const isc::log::MessageID& log_id);
 
-        /**
-         * \brief Checks if something lives below this domain.
-         *
-         * This looks if there's any subdomain of the given name. It can be
-         * used to test if domain is empty non-terminal.
-         *
-         * \param name The domain to check.
-         */
+        /// \brief Checks if something lives below this domain.
+        ///
+        /// This looks if there's any subdomain of the given name. It can be
+        /// used to test if domain is empty non-terminal.
+        ///
+        /// \param name The domain to check.
+        ///
+        /// \return true if the name has subdomains, false if not.
         bool hasSubdomains(const std::string& name);
 
         /**
diff --git a/src/lib/datasrc/datasrc_messages.mes b/src/lib/datasrc/datasrc_messages.mes
index d59454a..100476e 100644
--- a/src/lib/datasrc/datasrc_messages.mes
+++ b/src/lib/datasrc/datasrc_messages.mes
@@ -78,6 +78,13 @@ different TTL values. This isn't allowed on the wire and is considered
 an error, so we set it to the lowest value we found (but we don't modify the
 database). The data in database should be checked and fixed.
 
+% DATASRC_DATABASE_FOUND_CNAME search in datasource %1 for %2/%3/%4 resulted in CNAME %5
+When searching the domain for a name a CNAME was found at that name.  Even
+though it was not the RR type being sought, it is returned.  If the query
+of the database was issued by a result searching for the name, the return of
+the CNAME record will cause that resolver to issue another query for the
+target of the CNAME.
+
 % DATASRC_DATABASE_FOUND_DELEGATION Found delegation at %2 in %1
 When searching for a domain, the program met a delegation to a different zone
 at the given domain name. It will return that one instead.
@@ -93,9 +100,10 @@ place in the domain space at the given domain name. It will return that one
 instead.
 
 % DATASRC_DATABASE_FOUND_EMPTY_NONTERMINAL empty non-terminal %2 in %1
-The domain name doesn't have any RRs, so it doesn't exist in the database.
-However, it has a subdomain, so it exists in the DNS address space. So we
-return NXRRSET instead of NXDOMAIN.
+The domain name does not have any RRs associated with it, so it doesn't
+exist in the database.  However, it has a subdomain, so it does exist
+in the DNS address space. This type of domain is known an an "empty
+non-terminal" and so we return NXRRSET instead of NXDOMAIN.
 
 % DATASRC_DATABASE_FOUND_NXDOMAIN search in datasource %1 resulted in NXDOMAIN for %2/%3/%4
 The data returned by the database backend did not contain any data for the given
@@ -105,17 +113,16 @@ domain name, class and type.
 The data returned by the database backend contained data for the given domain
 name and class, but not for the given type.
 
+% DATASRC_DATABASE_FOUND_NXRRSET_NSEC search in datasource %1 for %2/%3/%4 resulted in RRset %5
+A search in the database for RRs for the specified name, type and class has
+located RRs that match the name and class but not the type.  DNSSEC information
+has been requested, but there is no NSEC record corresponding to the node.
+
 % DATASRC_DATABASE_FOUND_RRSET search in datasource %1 resulted in RRset %2
 The data returned by the database backend contained data for the given domain
 name, and it either matches the type or has a relevant type. The RRset that is
 returned is printed.
 
-% DATASRC_DATABASE_FOUND_CNAME search in datasource %1 for %2/%3/%4 resulted in CNAME %5
-(TBD)
-
-% DATASRC_DATABASE_FOUND_NXRRSET_NSEC search in datasource %1 for %2/%3/%4 resulted in RRset %5
-(TBD)
-
 % DATASRC_DATABASE_ITERATE iterating zone %1
 The program is reading the whole zone, eg. not searching for data, but going
 through each of the RRsets there.
@@ -133,6 +140,41 @@ were found to be different. This isn't allowed on the wire and is considered
 an error, so we set it to the lowest value we found (but we don't modify the
 database). The data in database should be checked and fixed.
 
+% DATASRC_DATABASE_UPDATER_COMMIT updates committed for '%1/%2' on %3
+Debug information.  A set of updates to a zone has been successfully
+committed to the corresponding database backend.  The zone name,
+its class and the database name are printed.
+
+% DATASRC_DATABASE_UPDATER_CREATED zone updater created for '%1/%2' on %3
+Debug information.  A zone updater object is created to make updates to
+the shown zone on the shown backend database.
+
+% DATASRC_DATABASE_UPDATER_DESTROYED zone updater destroyed for '%1/%2' on %3
+Debug information.  A zone updater object is destroyed, either successfully
+or after failure of, making updates to the shown zone on the shown backend
+database.
+
+% DATASRC_DATABASE_UPDATER_ROLLBACK zone updates roll-backed for '%1/%2' on %3
+A zone updater is being destroyed without committing the changes.
+This would typically mean the update attempt was aborted due to some
+error, but may also be a bug of the application that forgets committing
+the changes.  The intermediate changes made through the updater won't
+be applied to the underlying database.  The zone name, its class, and
+the underlying database name are shown in the log message.
+
+% DATASRC_DATABASE_UPDATER_ROLLBACKFAIL failed to roll back zone updates for '%1/%2' on %3: %4
+A zone updater is being destroyed without committing the changes to
+the database, and attempts to rollback incomplete updates, but it
+unexpectedly fails.  The higher level implementation does not expect
+it to fail, so this means either a serious operational error in the
+underlying data source (such as a system failure of a database) or
+software bug in the underlying data source implementation.  In either
+case if this message is logged the administrator should carefully
+examine the underlying data source to see what exactly happens and
+whether the data is still valid.  The zone name, its class, and the
+underlying database name as well as the error message thrown from the
+database module are shown in the log message.
+
 % DATASRC_DATABASE_WILDCARD constructing RRset %3 from wildcard %2 in %1
 The database doesn't contain directly matching domain, but it does contain a
 wildcard one which is being used to synthesize the answer.
@@ -265,7 +307,7 @@ Debug information. The requested record was found.
 
 % DATASRC_MEM_SUPER_STOP stopped at superdomain '%1', domain '%2' is empty
 Debug information. The search stopped at a superdomain of the requested
-domain. The domain is a empty nonterminal, therefore it is treated  as NXRRSET
+domain. The domain is an empty nonterminal, therefore it is treated  as NXRRSET
 case (eg. the domain exists, but it doesn't have the requested record type).
 
 % DATASRC_MEM_SWAP swapping contents of two zone representations ('%1' and '%2')
@@ -493,12 +535,12 @@ enough information for it.  The code is 1 for error, 2 for not implemented.
 % DATASRC_SQLITE_CLOSE closing SQLite database
 Debug information. The SQLite data source is closing the database file.
 
-% DATASRC_SQLITE_CONNOPEN Opening sqlite database file '%1'
-The database file is being opened so it can start providing data.
-
 % DATASRC_SQLITE_CONNCLOSE Closing sqlite database
 The database file is no longer needed and is being closed.
 
+% DATASRC_SQLITE_CONNOPEN Opening sqlite database file '%1'
+The database file is being opened so it can start providing data.
+
 % DATASRC_SQLITE_CREATE SQLite data source created
 Debug information. An instance of SQLite data source is being created.
 
@@ -601,38 +643,3 @@ data source.
 % DATASRC_UNEXPECTED_QUERY_STATE unexpected query state
 This indicates a programming error. An internal task of unknown type was
 generated.
-
-% DATASRC_DATABASE_UPDATER_CREATED zone updater created for '%1/%2' on %3
-Debug information.  A zone updater object is created to make updates to
-the shown zone on the shown backend database.
-
-% DATASRC_DATABASE_UPDATER_DESTROYED zone updater destroyed for '%1/%2' on %3
-Debug information.  A zone updater object is destroyed, either successfully
-or after failure of, making updates to the shown zone on the shown backend
-database.
-
-%DATASRC_DATABASE_UPDATER_ROLLBACK zone updates roll-backed for '%1/%2' on %3
-A zone updater is being destroyed without committing the changes.
-This would typically mean the update attempt was aborted due to some
-error, but may also be a bug of the application that forgets committing
-the changes.  The intermediate changes made through the updater won't
-be applied to the underlying database.  The zone name, its class, and
-the underlying database name are shown in the log message.
-
-%DATASRC_DATABASE_UPDATER_ROLLBACKFAIL failed to roll back zone updates for '%1/%2' on %3: %4
-A zone updater is being destroyed without committing the changes to
-the database, and attempts to rollback incomplete updates, but it
-unexpectedly fails.  The higher level implementation does not expect
-it to fail, so this means either a serious operational error in the
-underlying data source (such as a system failure of a database) or
-software bug in the underlying data source implementation.  In either
-case if this message is logged the administrator should carefully
-examine the underlying data source to see what exactly happens and
-whether the data is still valid.  The zone name, its class, and the
-underlying database name as well as the error message thrown from the
-database module are shown in the log message.
-
-% DATASRC_DATABASE_UPDATER_COMMIT updates committed for '%1/%2' on %3
-Debug information.  A set of updates to a zone has been successfully
-committed to the corresponding database backend.  The zone name,
-its class and the database name are printed.
diff --git a/tools/reorder_message_file.py b/tools/reorder_message_file.py
new file mode 100644
index 0000000..4829fc4
--- /dev/null
+++ b/tools/reorder_message_file.py
@@ -0,0 +1,196 @@
+# Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# Reorder Message File
+#
+# Reads a message file into memory, then outputs it with the messages and
+# associated descriptions in alphabetical order.
+#
+# Invocation:
+# The code is invoked using the command line:
+#
+# python reorder.py message_file
+#
+# Output is written to stdout.
+
+import sys
+
+def removeEmptyLeadingTrailing(lines):
+    """
+    Removes leading and trailing empty lines.
+
+    A list of strings is passed as argument, some of which may be empty.
+    This function removes from the start and end of the list a contiguous
+    sequence of empty lines and returns the result.  Embedded sequences of
+    empty lines are not touched.
+
+    Parameters:
+    lines List of strings to be modified.
+
+    Return:
+    Input list of strings with leading/trailing blank line sequences
+    removed.
+    """
+
+    retlines = []
+
+    # Dispose of degenerate case of empty array
+    if len(lines) == 0:
+        return retlines
+
+    # Search for first non-blank line
+    start = 0
+    while start < len(lines):
+        if len(lines[start]) > 0:
+            break
+        start = start + 1
+
+    # Handle case when entire list is empty
+    if start >= len(lines):
+        return retlines
+
+    # Search for last non-blank line
+    finish = len(lines) - 1
+    while finish >= 0:
+        if len(lines[finish]) > 0:
+            break
+        finish = finish - 1
+
+    retlines = lines[start:finish + 1]
+    return retlines
+
+
+def canonicalise_message_line(line):
+    """
+    Given a line known to start with the '%' character (i.e. a line
+    introducing a message), canonicalise it by ensuring that the result
+    is of the form '%<single-space>MESSAGE_IDENTIFIER<single-space>text'.
+
+    Parameters:
+    line - input line.  Known to start with a '%' and to have leading
+           and trailing spaces removed.
+
+    Return:
+    Canonicalised line.
+    """
+    # Cope with degenerate case of a single "%"
+    if len(line) == 1:
+        return line
+
+    # Get the rest of the line
+    line = line[1:].lstrip()
+
+    # Extract the first word (the message ID)
+    words = line.split()
+    message_line = "% " + words[0]
+    
+    # ... and now the rest of the line
+    if len(line) > len(words[0]):
+        message_line = message_line + " " + line[len(words[0]):].lstrip()
+
+    return message_line
+
+
+def make_dict(lines):
+    """
+    Split the lines into segments starting with the message definition and
+    place into a dictionary.
+
+    Parameters:
+    lines - list of lines containing the text of the message file (less the
+            header).
+
+    Returns:
+    dictionary - map of the messages, keyed by the line that holds the message
+                 ID.
+    """
+
+    dictionary = {}
+
+    message_key = canonicalise_message_line(lines[0])
+    message_lines = [message_key]
+    index = 1;
+    while index < len(lines):
+        if lines[index].startswith("%"):
+            # Start of new message
+            dictionary[message_key] = removeEmptyLeadingTrailing(message_lines)
+            message_key = canonicalise_message_line(lines[index])
+            message_lines = [message_key]
+        else:
+            message_lines.append(lines[index])
+        
+        index = index + 1
+
+    dictionary[message_key] = removeEmptyLeadingTrailing(message_lines)
+
+    return dictionary
+
+        
+def print_dict(dictionary):
+    """
+    Prints the dictionary with a blank line between entries.
+
+    Parameters:
+    dicitionary - Map holding the message dictionary
+    """
+    count = 0
+    for msgid in sorted(dictionary):
+
+        # Blank line before all entries but the first
+        if count > 0:
+            print("")
+        count = count + 1
+
+        # ... and the entry itself.
+        for l in dictionary[msgid]:
+            print(l.strip())
+
+
+def processFile(filename):
+    """
+    Processes a file by reading it and searching for the first line starting
+    with the '%' sign.  Everything before that line is treated as the file
+    header and is copied to the output with leading and trailing spaces removed.
+    After that, each message block is read and stored for later sorting.
+
+    Parameters:
+    filename     Name of the message file to process
+    """
+    lines = open(filename).read().splitlines();
+
+    # Search for the first line starting with the percent character.  Everything
+    # before it is considered the file header and is copied to the output with
+    # leading and trailing spaces removed.
+    index = 0
+    while index < len(lines):
+        if lines[index].startswith("%"):
+            break
+        print(lines[index].strip())
+        index = index + 1
+
+    # Now put the remaining lines into the message dictionary
+    dictionary = make_dict(lines[index:])
+
+    # ...and print it
+    print_dict(dictionary)
+
+
+# Main program
+if __name__ == "__main__":
+
+    # Read the files and load the data
+    if len(sys.argv) != 2:
+        print "Usage: python reorder.py message_file"
+    else:
+        processFile(sys.argv[1])




More information about the bind10-changes mailing list