LCOV - code coverage report
Current view: top level - datasrc - memory_datasrc.cc (source / functions) Hit Total Coverage
Test: report.info Lines: 623 638 97.6 %
Date: 2012-05-15 Functions: 81 86 94.2 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 932 1687 55.2 %

           Branch data     Line data    Source code
       1                 :            : // Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
       2                 :            : //
       3                 :            : // Permission to use, copy, modify, and/or distribute this software for any
       4                 :            : // purpose with or without fee is hereby granted, provided that the above
       5                 :            : // copyright notice and this permission notice appear in all copies.
       6                 :            : //
       7                 :            : // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
       8                 :            : // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
       9                 :            : // AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
      10                 :            : // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
      11                 :            : // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
      12                 :            : // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
      13                 :            : // PERFORMANCE OF THIS SOFTWARE.
      14                 :            : 
      15                 :            : #include <exceptions/exceptions.h>
      16                 :            : 
      17                 :            : #include <dns/name.h>
      18                 :            : #include <dns/nsec3hash.h>
      19                 :            : #include <dns/rdataclass.h>
      20                 :            : #include <dns/rrclass.h>
      21                 :            : #include <dns/rrsetlist.h>
      22                 :            : #include <dns/masterload.h>
      23                 :            : 
      24                 :            : #include <datasrc/memory_datasrc.h>
      25                 :            : #include <datasrc/rbtree.h>
      26                 :            : #include <datasrc/rbnode_rrset.h>
      27                 :            : #include <datasrc/logger.h>
      28                 :            : #include <datasrc/iterator.h>
      29                 :            : #include <datasrc/data_source.h>
      30                 :            : #include <datasrc/factory.h>
      31                 :            : 
      32                 :            : #include <boost/function.hpp>
      33                 :            : #include <boost/shared_ptr.hpp>
      34                 :            : #include <boost/scoped_ptr.hpp>
      35                 :            : #include <boost/bind.hpp>
      36                 :            : #include <boost/foreach.hpp>
      37                 :            : 
      38                 :            : #include <algorithm>
      39                 :            : #include <map>
      40                 :            : #include <utility>
      41                 :            : #include <cctype>
      42                 :            : #include <cassert>
      43                 :            : 
      44                 :            : using namespace std;
      45                 :            : using namespace isc::dns;
      46                 :            : using namespace isc::dns::rdata;
      47                 :            : using boost::scoped_ptr;
      48                 :            : 
      49                 :            : namespace isc {
      50                 :            : namespace datasrc {
      51                 :            : 
      52                 :            : using namespace internal;
      53                 :            : 
      54                 :            : namespace {
      55                 :            : // Some type aliases
      56                 :            : 
      57                 :            : // A functor type used for loading.
      58                 :            : typedef boost::function<void(ConstRRsetPtr)> LoadCallback;
      59                 :            : 
      60                 :            : // RRset specified for this implementation
      61                 :            : typedef boost::shared_ptr<internal::RBNodeRRset> RBNodeRRsetPtr;
      62                 :            : typedef boost::shared_ptr<const internal::RBNodeRRset> ConstRBNodeRRsetPtr;
      63                 :            : 
      64                 :            : /*
      65                 :            :  * Each domain consists of some RRsets. They will be looked up by the
      66                 :            :  * RRType.
      67                 :            :  *
      68                 :            :  * The use of map is questionable with regard to performance - there'll
      69                 :            :  * be usually only few RRsets in the domain, so the log n benefit isn't
      70                 :            :  * much and a vector/array might be faster due to its simplicity and
      71                 :            :  * continuous memory location. But this is unlikely to be a performance
      72                 :            :  * critical place and map has better interface for the lookups, so we use
      73                 :            :  * that.
      74                 :            :  */
      75                 :            : typedef map<RRType, ConstRBNodeRRsetPtr> Domain;
      76                 :            : typedef Domain::value_type DomainPair;
      77                 :            : typedef boost::shared_ptr<Domain> DomainPtr;
      78                 :            : // The tree stores domains
      79                 :            : typedef RBTree<Domain> DomainTree;
      80                 :            : typedef RBNode<Domain> DomainNode;
      81                 :            : 
      82                 :            : // In the following dedicated namespace we define a few application-specific
      83                 :            : // RBNode flags.  We use a separate namespace so we can consolidate the
      84                 :            : // definition in a single place, which would hopefully reduce the risk of
      85                 :            : // collisions.
      86                 :            : // (Note: it's within an unnamed namespace, so effectively private.)
      87                 :            : namespace domain_flag {
      88                 :            : // This flag indicates the node is at a "wildcard level" (in short, it means
      89                 :            : // one of the node's immediate child is a wildcard).  See addWildcards()
      90                 :            : // for more details.
      91                 :            : const DomainNode::Flags WILD = DomainNode::FLAG_USER1;
      92                 :            : 
      93                 :            : // This flag is used for additional record shortcut.  If a node has this
      94                 :            : // flag, it's under a zone cut for a delegation to a child zone.
      95                 :            : // Note: for a statically built zone this information is stable, but if we
      96                 :            : // change the implementation to be dynamically modifiable, it may not be
      97                 :            : // realistic to keep this flag update for all affected nodes, and we may
      98                 :            : // have to reconsider the mechanism.
      99                 :            : const DomainNode::Flags GLUE = DomainNode::FLAG_USER2;
     100                 :            : 
     101                 :            : // This flag indicates the node is generated as a result of wildcard
     102                 :            : // expansion.  In this implementation, this flag can be set only in
     103                 :            : // the separate auxiliary tree of ZoneData (see the structure description).
     104                 :            : const DomainNode::Flags WILD_EXPANDED = DomainNode::FLAG_USER3;
     105                 :            : };
     106                 :            : 
     107                 :            : // Separate storage for NSEC3 RRs (and their RRSIGs).  It's an STL map
     108                 :            : // from string to the NSEC3 RRset.  The map key is the first label
     109                 :            : // (upper cased) of the owner name of the corresponding NSEC3 (i.e., map
     110                 :            : // value).  We can use  the standard string comparison (if the comparison
     111                 :            : // target is also upper cased) due to the nature of NSEC3 owner names.
     112                 :            : //
     113                 :            : // Note: We maintain the RRsets in the form of RBNodeRRset even if they are
     114                 :            : // not stored in the RB tree.  The reason is because comparison can be
     115                 :            : // more efficient if we make sure all RRsets returned from this module are
     116                 :            : // of the same type.
     117                 :            : typedef map<string, ConstRBNodeRRsetPtr> NSEC3Map;
     118                 :            : typedef NSEC3Map::value_type NSEC3Pair;
     119                 :            : 
     120                 :            : // Actual zone data: Essentially a set of zone's RRs.  This is defined as
     121                 :            : // a separate structure so that it'll be replaceable on reload.
     122 [ +  - ][ +  - ]:        214 : struct ZoneData {
     123                 :        214 :     ZoneData(const Name& origin) :
     124                 :            :         domains_(true),
     125                 :            :         origin_data_(NULL),
     126                 :          0 :         nsec_signed_(false)
     127                 :            :     {
     128                 :            :         // We create the node for origin (it needs to exist anyway in future)
     129         [ +  - ]:        214 :         domains_.insert(origin, &origin_data_);
     130 [ +  - ][ +  - ]:        214 :         DomainPtr origin_domain(new Domain);
     131                 :        214 :         origin_data_->setData(origin_domain);
     132                 :        214 :     }
     133                 :            : 
     134                 :            :     // The main data (name + RRsets)
     135                 :            :     DomainTree domains_;
     136                 :            : 
     137                 :            :     // An auxiliary tree for wildcard expanded data used in additional data
     138                 :            :     // processing.  It contains names like "ns.wild.example" in the following
     139                 :            :     // example:
     140                 :            :     // child.wild.example. NS ns.wild.example.
     141                 :            :     // *.wild.example IN AAAA 2001:db8::1234
     142                 :            :     // (and there's no exact ns.wild.example. in the zone).  This tree contains
     143                 :            :     // such names with a copy of the RRsets of the matching wildcard name
     144                 :            :     // with its owner name expanded, e.g.:
     145                 :            :     // ns.wild.example. IN AAAA 2001:db8::1234
     146                 :            :     // In theory, this tree could have many such wildcard-expandable names,
     147                 :            :     // each of which has a copy of the original list of RRsets.  In practice,
     148                 :            :     // however, it should be very rare that names for additional section
     149                 :            :     // processing are subject to wildcard expansion, so in most cases this tree
     150                 :            :     // should be even empty, and even if it has content it should be very
     151                 :            :     // small.
     152                 :            : private:
     153                 :            :     scoped_ptr<DomainTree> aux_wild_domains_;
     154                 :            : public:
     155                 :         65 :     DomainTree& getAuxWildDomains() {
     156         [ +  + ]:         65 :         if (!aux_wild_domains_) {
     157                 :         13 :             aux_wild_domains_.reset(new DomainTree);
     158                 :            :         }
     159                 :         65 :         return (*aux_wild_domains_);
     160                 :            :     }
     161                 :            : 
     162                 :            :     // Shortcut to the origin node, which should always exist
     163                 :            :     DomainNode* origin_data_;
     164                 :            : 
     165                 :            :     // The optional NSEC3 related data
     166                 :         35 :     struct NSEC3Data {
     167                 :            :         NSEC3Data(const generic::NSEC3PARAM& nsec3param) :
     168         [ +  - ]:         20 :             hash_(NSEC3Hash::create(nsec3param))
     169                 :            :         {}
     170                 :            :         NSEC3Data(const generic::NSEC3& nsec3) :
     171 [ +  - ][ #  # ]:         15 :             hash_(NSEC3Hash::create(nsec3))
     172                 :            :         {}
     173                 :            :         NSEC3Map map_;    // Actual NSEC3 RRs
     174                 :            :         const scoped_ptr<NSEC3Hash> hash_; // hash parameter/calculator
     175                 :            :     };
     176                 :            :     scoped_ptr<NSEC3Data> nsec3_data_; // non NULL only when it's NSEC3 signed
     177                 :            :     bool nsec_signed_; // True if there's at least one NSEC record
     178                 :            : 
     179                 :            :     // This templated structure encapsulates the find result of findNode()
     180                 :            :     // method (also templated) below.
     181                 :            :     // The template parameter is expected to be either 'const DomainNode' or
     182                 :            :     // 'DomainNode' (to avoid misuse the template definition itself is kept
     183                 :            :     // private - we only expose expected typedefs).  The former is expected
     184                 :            :     // to be used for lookups, and the latter is expected to be used for
     185                 :            :     // constructing the zone.
     186                 :            : private:
     187                 :            :     template <typename NodeType>
     188                 :        734 :     struct FindNodeResultBase {
     189                 :            :         // Bitwise flags to represent supplemental information of the
     190                 :            :         // search result:
     191                 :            :         // Search resulted in a wildcard match.
     192                 :            :         static const unsigned int FIND_WILDCARD = 1;
     193                 :            :         // Search encountered a zone cut due to NS but continued to look for
     194                 :            :         // a glue.
     195                 :            :         static const unsigned int FIND_ZONECUT = 2;
     196                 :            : 
     197                 :            :         FindNodeResultBase(ZoneFinder::Result code_param,
     198                 :            :                            NodeType* node_param,
     199                 :            :                            ConstRBNodeRRsetPtr rrset_param,
     200                 :            :                            unsigned int flags_param = 0) :
     201                 :            :             code(code_param), node(node_param), rrset(rrset_param),
     202                 :       1468 :             flags(flags_param)
     203                 :            :         {}
     204                 :            :         const ZoneFinder::Result code;
     205                 :            :         NodeType* const node;
     206                 :            :         ConstRBNodeRRsetPtr const rrset;
     207                 :            :         const unsigned int flags;
     208                 :            :     };
     209                 :            : public:
     210                 :            :     typedef FindNodeResultBase<const DomainNode> FindNodeResult;
     211                 :            :     typedef FindNodeResultBase<DomainNode> FindMutableNodeResult;
     212                 :            : 
     213                 :            :     // Identify the RBTree node that best matches the given name.
     214                 :            :     // See implementation notes below.
     215                 :            :     //
     216                 :            :     // The caller should pass an empty node_path, and it will contain the
     217                 :            :     // search context (all ancestor nodes that the underlying RBTree search
     218                 :            :     // traverses, and how the search stops) for possible later use at the
     219                 :            :     // caller side.
     220                 :            :     template <typename ResultType>
     221                 :            :     ResultType findNode(const Name& name,
     222                 :            :                         RBTreeNodeChain<Domain>& node_path,
     223                 :            :                         ZoneFinder::FindOptions options) const;
     224                 :            : 
     225                 :            :     // A helper method for NSEC-signed zones.  It searches the zone for
     226                 :            :     // the "closest" NSEC corresponding to the search context stored in
     227                 :            :     // node_path (it should contain sufficient information to identify the
     228                 :            :     // previous name of the query name in the zone).  In some cases the
     229                 :            :     // immediate closest name may not have NSEC (when it's under a zone cut
     230                 :            :     // for glue records, or even when the zone is partly broken), so this
     231                 :            :     // method continues the search until it finds a name that has NSEC,
     232                 :            :     // and returns the one found first.  Due to the prerequisite (see below),
     233                 :            :     // it should always succeed.
     234                 :            :     //
     235                 :            :     // node_path must store valid search context (in practice, it's expected
     236                 :            :     // to be set by findNode()); otherwise the underlying RBTree implementation
     237                 :            :     // throws.
     238                 :            :     //
     239                 :            :     // If the zone is not considered NSEC-signed or DNSSEC records were not
     240                 :            :     // required in the original search context (specified in options), this
     241                 :            :     // method doesn't bother to find NSEC, and simply returns NULL.  So, by
     242                 :            :     // definition of "NSEC-signed", when it really tries to find an NSEC it
     243                 :            :     // should succeed; there should be one at least at the zone origin.
     244                 :            :     ConstRBNodeRRsetPtr
     245                 :            :     getClosestNSEC(RBTreeNodeChain<Domain>& node_path,
     246                 :            :                    ZoneFinder::FindOptions options) const;
     247                 :            : };
     248                 :            : 
     249                 :            : ConstRBNodeRRsetPtr
     250                 :        108 : ZoneData::getClosestNSEC(RBTreeNodeChain<Domain>& node_path,
     251                 :            :                          ZoneFinder::FindOptions options) const
     252                 :            : {
     253 [ +  + ][ +  + ]:        108 :     if (!nsec_signed_ || (options & ZoneFinder::FIND_DNSSEC) == 0) {
     254                 :            :         return (ConstRBNodeRRsetPtr());
     255                 :            :     }
     256                 :            : 
     257                 :            :     const DomainNode* prev_node;
     258         [ +  - ]:         54 :     while ((prev_node = domains_.previousNode(node_path)) != NULL) {
     259         [ +  + ]:         54 :         if (!prev_node->isEmpty()) {
     260                 :            :             const Domain::const_iterator found =
     261                 :         36 :                 prev_node->getData()->find(RRType::NSEC());
     262         [ +  + ]:         36 :             if (found != prev_node->getData()->end()) {
     263                 :         17 :                 return (found->second);
     264                 :            :             }
     265                 :            :         }
     266                 :            :     }
     267                 :            :     // This must be impossible and should be an internal bug.
     268                 :            :     // See the description at the method declaration.
     269                 :        108 :     assert(false);
     270                 :            :     // Even though there is an assert here, strict compilers
     271                 :            :     // will still need some return value.
     272                 :            :     return (ConstRBNodeRRsetPtr());
     273                 :            : }
     274                 :            : 
     275                 :            : /// Maintain intermediate data specific to the search context used in
     276                 :            : /// \c find().
     277                 :            : ///
     278                 :            : /// It will be passed to \c cutCallback() (see below) and record a possible
     279                 :            : /// zone cut node and related RRset (normally NS or DNAME).
     280                 :        745 : struct FindState {
     281                 :            :     FindState(bool glue_ok) :
     282                 :            :         zonecut_node_(NULL),
     283                 :            :         dname_node_(NULL),
     284                 :       1490 :         glue_ok_(glue_ok)
     285                 :            :     {}
     286                 :            : 
     287                 :            :     // These will be set to a domain node of the highest delegation point,
     288                 :            :     // if any.  In fact, we could use a single variable instead of both.
     289                 :            :     // But then we would need to distinquish these two cases by something
     290                 :            :     // else and it seemed little more confusing when this was written.
     291                 :            :     const DomainNode* zonecut_node_;
     292                 :            :     const DomainNode* dname_node_;
     293                 :            : 
     294                 :            :     // Delegation RRset (NS or DNAME), if found.
     295                 :            :     ConstRBNodeRRsetPtr rrset_;
     296                 :            : 
     297                 :            :     // Whether to continue search below a delegation point.
     298                 :            :     // Set at construction time.
     299                 :            :     const bool glue_ok_;
     300                 :            : };
     301                 :            : 
     302                 :            : // A callback called from possible zone cut nodes and nodes with DNAME.
     303                 :            : // This will be passed from findNode() to \c RBTree::find().
     304                 :        148 : bool cutCallback(const DomainNode& node, FindState* state) {
     305                 :            :     // We need to look for DNAME first, there's allowed case where
     306                 :            :     // DNAME and NS coexist in the apex. DNAME is the one to notice,
     307                 :            :     // the NS is authoritative, not delegation (corner case explicitly
     308                 :            :     // allowed by section 3 of 2672)
     309                 :            :     const Domain::const_iterator found_dname(node.getData()->find(
     310                 :        148 :                                                  RRType::DNAME()));
     311         [ +  + ]:        148 :     if (found_dname != node.getData()->end()) {
     312         [ +  - ]:         17 :         LOG_DEBUG(logger, DBG_TRACE_DETAILED, DATASRC_MEM_DNAME_ENCOUNTERED);
     313                 :         17 :         state->dname_node_ = &node;
     314                 :         17 :         state->rrset_ = found_dname->second;
     315                 :            :         // No more processing below the DNAME (RFC 2672, section 3
     316                 :            :         // forbids anything to exist below it, so there's no need
     317                 :            :         // to actually search for it). This is strictly speaking
     318                 :            :         // a different way than described in 4.1 of that RFC,
     319                 :            :         // but because of the assumption in section 3, it has the
     320                 :            :         // same behaviour.
     321                 :        148 :         return (true);
     322                 :            :     }
     323                 :            : 
     324                 :            :     // Look for NS
     325                 :        131 :     const Domain::const_iterator found_ns(node.getData()->find(RRType::NS()));
     326         [ +  - ]:        131 :     if (found_ns != node.getData()->end()) {
     327                 :            :         // We perform callback check only for the highest zone cut in the
     328                 :            :         // rare case of nested zone cuts.
     329         [ +  + ]:        131 :         if (state->zonecut_node_ != NULL) {
     330                 :            :             return (false);
     331                 :            :         }
     332                 :            : 
     333         [ +  - ]:        129 :         LOG_DEBUG(logger, DBG_TRACE_DETAILED, DATASRC_MEM_NS_ENCOUNTERED);
     334                 :            : 
     335                 :            :         // BIND 9 checks if this node is not the origin.  That's probably
     336                 :            :         // because it can support multiple versions for dynamic updates
     337                 :            :         // and IXFR, and it's possible that the callback is called at
     338                 :            :         // the apex and the DNAME doesn't exist for a particular version.
     339                 :            :         // It cannot happen for us (at least for now), so we don't do
     340                 :            :         // that check.
     341                 :        129 :         state->zonecut_node_ = &node;
     342                 :        129 :         state->rrset_ = found_ns->second;
     343                 :            : 
     344                 :            :         // Unless glue is allowed the search stops here, so we return
     345                 :            :         // false; otherwise return true to continue the search.
     346                 :        129 :         return (!state->glue_ok_);
     347                 :            :     }
     348                 :            : 
     349                 :            :     // This case should not happen because we enable callback only
     350                 :            :     // when we add an RR searched for above.
     351                 :          0 :     assert(0);
     352                 :            :     // This is here to avoid warning (therefore compilation error)
     353                 :            :     // in case assert is turned off. Otherwise we could get "Control
     354                 :            :     // reached end of non-void function".
     355                 :            :     return (false);
     356                 :            : }
     357                 :            : 
     358                 :            : // Implementation notes: this method identifies an RBT node that best matches
     359                 :            : // the give name in terms of DNS query handling.  In many cases,
     360                 :            : // DomainTree::find() will result in EXACTMATCH or PARTIALMATCH (note that
     361                 :            : // the given name is generally expected to be contained in the zone, so
     362                 :            : // even if it doesn't exist, it should at least match the zone origin).
     363                 :            : // If it finds an exact match, that's obviously the best one.  The partial
     364                 :            : // match case is more complicated.
     365                 :            : //
     366                 :            : // We first need to consider the case where search hits a delegation point,
     367                 :            : // either due to NS or DNAME.  They are indicated as either dname_node_ or
     368                 :            : // zonecut_node_ being non NULL.  Usually at most one of them will be
     369                 :            : // something else than NULL (it might happen both are NULL, in which case we
     370                 :            : // consider it NOT FOUND). There's one corner case when both might be
     371                 :            : // something else than NULL and it is in case there's a DNAME under a zone
     372                 :            : // cut and we search in glue OK mode ‒ in that case we don't stop on the
     373                 :            : // domain with NS and ignore it for the answer, but it gets set anyway. Then
     374                 :            : // we find the DNAME and we need to act by it, therefore we first check for
     375                 :            : // DNAME and then for NS. In all other cases it doesn't matter, as at least
     376                 :            : // one of them is NULL.
     377                 :            : //
     378                 :            : // Next, we need to check if the RBTree search stopped at a node for a
     379                 :            : // subdomain of the search name (so the comparison result that stopped the
     380                 :            : // search is "SUPERDOMAIN"), it means the stopping node is an empty
     381                 :            : // non-terminal node.  In this case the search name is considered to exist
     382                 :            : // but no data should be found there.
     383                 :            : //
     384                 :            : // If none of above is the case, we then consider whether there's a matching
     385                 :            : // wildcard.  DomainTree::find() records the node if it encounters a
     386                 :            : // "wildcarding" node, i.e., the immediate ancestor of a wildcard name
     387                 :            : // (e.g., wild.example.com for *.wild.example.com), and returns it if it
     388                 :            : // doesn't find any node that better matches the query name.  In this case
     389                 :            : // we'll check if there's indeed a wildcard below the wildcarding node.
     390                 :            : //
     391                 :            : // Note, first, that the wildcard is checked after the empty
     392                 :            : // non-terminal domain case above, because if that one triggers, it
     393                 :            : // means we should not match according to 4.3.3 of RFC 1034 (the query
     394                 :            : // name is known to exist).
     395                 :            : //
     396                 :            : // Before we try to find a wildcard, we should check whether there's
     397                 :            : // an existing node that would cancel the wildcard match.  If
     398                 :            : // DomainTree::find() stopped at a node which has a common ancestor
     399                 :            : // with the query name, it might mean we are comparing with a
     400                 :            : // non-wildcard node. In that case, we check which part is common. If
     401                 :            : // we have something in common that lives below the node we got (the
     402                 :            : // one above *), then we should cancel the match according to section
     403                 :            : // 4.3.3 of RFC 1034 (as the name between the wildcard domain and the
     404                 :            : // query name is known to exist).
     405                 :            : //
     406                 :            : // If there's no node below the wildcarding node that shares a common ancestor
     407                 :            : // of the query name, we can conclude the wildcard is the best match.
     408                 :            : // We'll then identify the wildcard node via an incremental search.  Note that
     409                 :            : // there's no possibility that the query name is at an empty non terminal
     410                 :            : // node below the wildcarding node at this stage; that case should have been
     411                 :            : // caught above.
     412                 :            : //
     413                 :            : // If none of the above succeeds, we conclude the name doesn't exist in
     414                 :            : // the zone.
     415                 :            : template <typename ResultType>
     416                 :            : ResultType
     417                 :        745 : ZoneData::findNode(const Name& name, RBTreeNodeChain<Domain>& node_path,
     418                 :            :                    ZoneFinder::FindOptions options) const
     419                 :            : {
     420                 :        745 :     DomainNode* node = NULL;
     421                 :        745 :     FindState state((options & ZoneFinder::FIND_GLUE_OK) != 0);
     422                 :            : 
     423                 :            :     const DomainTree::Result result =
     424 [ +  - ][ +  - ]:        745 :         domains_.find(name, &node, node_path, cutCallback, &state);
     425                 :            :     const unsigned int zonecut_flag =
     426 [ +  + ][ +  + ]:        745 :         (state.zonecut_node_ != NULL) ? FindNodeResult::FIND_ZONECUT : 0;
     427 [ +  + ][ +  + ]:        745 :     if (result == DomainTree::EXACTMATCH) {
     428                 :            :         return (ResultType(ZoneFinder::SUCCESS, node, state.rrset_,
     429                 :        559 :                            zonecut_flag));
     430 [ +  - ][ +  + ]:        186 :     } else if (result == DomainTree::PARTIALMATCH) {
     431 [ -  + ][ -  + ]:        175 :         assert(node != NULL);
     432 [ +  + ][ +  + ]:        175 :         if (state.dname_node_ != NULL) { // DNAME
     433 [ +  - ][ +  - ]:         17 :             LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_DNAME_FOUND).
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     434                 :            :                 arg(state.rrset_->getName());
     435                 :            :             return (ResultType(ZoneFinder::DNAME, NULL, state.rrset_));
     436                 :            :         }
     437 [ -  + ][ +  + ]:        158 :         if (state.zonecut_node_ != NULL) { // DELEGATION due to NS
     438 [ #  # ][ #  # ]:         16 :             LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_DELEG_FOUND).
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     439                 :            :                 arg(state.rrset_->getName());
     440                 :            :             return (ResultType(ZoneFinder::DELEGATION, NULL, state.rrset_));
     441                 :            :         }
     442 [ -  + ][ +  + ]:        142 :         if (node_path.getLastComparisonResult().getRelation() ==
     443                 :            :             NameComparisonResult::SUPERDOMAIN) { // empty node, so NXRRSET
     444 [ #  # ][ #  # ]:         12 :             LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_SUPER_STOP).arg(name);
         [ #  # ][ #  # ]
         [ #  # ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     445                 :            :             return (ResultType(ZoneFinder::NXRRSET, node,
     446 [ #  # ][ +  - ]:         12 :                                getClosestNSEC(node_path, options)));
     447                 :            :         }
     448 [ +  - ][ -  + ]:        130 :         if (node->getFlag(domain_flag::WILD) && // maybe a wildcard, check only
         [ +  - ][ +  + ]
         [ +  + ][ +  + ]
     449                 :            :             (options & ZoneFinder::NO_WILDCARD) == 0) { // if not disabled.
     450 [ +  - ][ +  - ]:         91 :             if (node_path.getLastComparisonResult().getRelation() ==
         [ -  + ][ +  - ]
         [ +  + ][ +  + ]
     451                 :            :                 NameComparisonResult::COMMONANCESTOR &&
     452                 :            :                 node_path.getLastComparisonResult().getCommonLabels() > 1) {
     453                 :            :                 // Wildcard canceled.  Treat it as NXDOMAIN.
     454                 :            :                 // Note: Because the way the tree stores relative names, we
     455                 :            :                 // will have exactly one common label (the ".") in case we have
     456                 :            :                 // nothing common under the node we got, and we will get
     457                 :            :                 // more common labels otherwise (yes, this relies on the
     458                 :            :                 // internal RBTree structure, which leaks out through this
     459                 :            :                 // little bit).
     460 [ #  # ][ #  # ]:          8 :                 LOG_DEBUG(logger, DBG_TRACE_DATA,
         [ #  # ][ #  # ]
         [ #  # ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     461                 :            :                           DATASRC_MEM_WILDCARD_CANCEL).arg(name);
     462                 :            :                 return (ResultType(ZoneFinder::NXDOMAIN, NULL,
     463 [ #  # ][ +  - ]:          8 :                                    getClosestNSEC(node_path, options)));
     464                 :            :             }
     465                 :            :             // Now the wildcard should be the best match.
     466                 :            :             const Name wildcard(Name("*").concatenate(
     467 [ +  - ][ +  - ]:        166 :                                     node_path.getAbsoluteName()));
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     468                 :            : 
     469                 :            :             // Clear the node_path so that we don't keep incorrect (NSEC)
     470                 :            :             // context
     471                 :            :             node_path.clear();
     472                 :            :             DomainTree::Result result(domains_.find(wildcard, &node,
     473                 :        166 :                                                     node_path));
     474                 :            :             // Otherwise, why would the domain_flag::WILD be there if
     475                 :            :             // there was no wildcard under it?
     476 [ -  + ][ -  + ]:         83 :             assert(result == DomainTree::EXACTMATCH);
     477                 :            :             return (ResultType(ZoneFinder::SUCCESS, node, state.rrset_,
     478                 :            :                                FindNodeResult::FIND_WILDCARD |
     479                 :        166 :                                zonecut_flag));
     480                 :            :         }
     481                 :            :         // Nothing really matched.
     482 [ #  # ][ #  # ]:         39 :         LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_NOT_FOUND).arg(name);
         [ #  # ][ #  # ]
         [ #  # ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     483                 :            :         return (ResultType(ZoneFinder::NXDOMAIN, node,
     484 [ #  # ][ +  - ]:         39 :                            getClosestNSEC(node_path, options)));
     485                 :            :     } else {
     486                 :            :         // If the name is neither an exact or partial match, it is
     487                 :            :         // out of bailiwick, which is considered an error.
     488 [ #  # ][ #  # ]:         22 :         isc_throw(OutOfZone, name.toText() << " not in " <<
         [ #  # ][ #  # ]
         [ #  # ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     489                 :            :                              origin_data_->getName());
     490                 :            :     }
     491                 :            : }
     492                 :            : } // unnamed namespace
     493                 :            : 
     494                 :            : namespace internal {
     495                 :            : 
     496                 :            : /// \brief An encapsulation type for a pointer of an additional node
     497                 :            : /// associated with an \c RBNodeRRset object.
     498                 :            : ///
     499                 :            : /// Currently this is defined as a structure only so that it can declared
     500                 :            : /// in rbnode_rrset.h; this is essentially a pointer to \c DomainNode.
     501                 :            : /// In future, however, this structure may have other attributes.
     502                 :          0 : struct AdditionalNodeInfo {
     503                 :        423 :     explicit AdditionalNodeInfo(DomainNode* node) : node_(node) {}
     504                 :            :     DomainNode* node_;
     505                 :            : };
     506                 :            : 
     507                 :            : //
     508                 :            : // RBNodeRRset details
     509                 :            : //
     510                 :       2058 : struct RBNodeRRsetImpl {
     511                 :            : public:
     512                 :       4116 :     RBNodeRRsetImpl(const ConstRRsetPtr& rrset) : rrset_(rrset)
     513                 :            :     {}
     514                 :            : 
     515                 :            :     ConstRRsetPtr rrset_;     ///< Underlying RRset
     516                 :            :     scoped_ptr<vector<AdditionalNodeInfo> > additionals_;
     517                 :            : };
     518                 :            : 
     519                 :       2058 : RBNodeRRset::RBNodeRRset(const ConstRRsetPtr& rrset) :
     520         [ +  - ]:       2058 :     impl_(new RBNodeRRsetImpl(rrset))
     521                 :            : {
     522                 :       2058 : }
     523                 :            : 
     524                 :       4030 : RBNodeRRset::~RBNodeRRset() {
     525         [ +  - ]:       4116 :     delete impl_;
     526                 :       4030 : }
     527                 :            : 
     528                 :            : unsigned int
     529                 :         20 : RBNodeRRset::getRdataCount() const {
     530                 :         20 :     return (impl_->rrset_->getRdataCount());
     531                 :            : }
     532                 :            : 
     533                 :            : const Name&
     534                 :       4447 : RBNodeRRset::getName() const {
     535                 :       4447 :     return (impl_->rrset_->getName());
     536                 :            : }
     537                 :            : 
     538                 :            : const RRClass&
     539                 :        375 : RBNodeRRset::getClass() const {
     540                 :        375 :     return (impl_->rrset_->getClass());
     541                 :            : }
     542                 :            : 
     543                 :            : const RRType&
     544                 :      15013 : RBNodeRRset::getType() const {
     545                 :      15013 :     return (impl_->rrset_->getType());
     546                 :            : }
     547                 :            : 
     548                 :            : const RRTTL&
     549                 :        251 : RBNodeRRset::getTTL() const {
     550                 :        251 :     return (impl_->rrset_->getTTL());
     551                 :            : }
     552                 :            : 
     553                 :            : void
     554                 :          1 : RBNodeRRset::setName(const Name&) {
     555 [ +  - ][ +  - ]:          2 :     isc_throw(isc::NotImplemented, "RBNodeRRset::setName() not supported");
     556                 :            : }
     557                 :            : 
     558                 :            : void
     559                 :          1 : RBNodeRRset::setTTL(const RRTTL&) {
     560 [ +  - ][ +  - ]:          2 :     isc_throw(isc::NotImplemented, "RBNodeRRset::setTTL() not supported");
     561                 :            : }
     562                 :            : 
     563                 :            : string
     564                 :        335 : RBNodeRRset::toText() const {
     565                 :        335 :     return (impl_->rrset_->toText());
     566                 :            : }
     567                 :            : 
     568                 :            : unsigned int
     569                 :         14 : RBNodeRRset::toWire(AbstractMessageRenderer& renderer) const {
     570                 :         14 :     return (impl_->rrset_->toWire(renderer));
     571                 :            : }
     572                 :            : 
     573                 :            : unsigned int
     574                 :          2 : RBNodeRRset::toWire(isc::util::OutputBuffer& buffer) const {
     575                 :          2 :     return (impl_->rrset_->toWire(buffer));
     576                 :            : }
     577                 :            : 
     578                 :            : void
     579                 :          1 : RBNodeRRset::addRdata(ConstRdataPtr) {
     580 [ +  - ][ +  - ]:          2 :     isc_throw(isc::NotImplemented, "RBNodeRRset::addRdata() not supported");
     581                 :            : }
     582                 :            : 
     583                 :            : void
     584                 :          2 : RBNodeRRset::addRdata(const Rdata&) {
     585 [ +  - ][ +  - ]:          4 :     isc_throw(isc::NotImplemented, "RBNodeRRset::addRdata() not supported");
     586                 :            : }
     587                 :            : 
     588                 :            : RdataIteratorPtr
     589                 :       1665 : RBNodeRRset::getRdataIterator() const {
     590                 :       1665 :     return (impl_->rrset_->getRdataIterator());
     591                 :            : }
     592                 :            : 
     593                 :            : RRsetPtr
     594                 :        729 : RBNodeRRset::getRRsig() const {
     595                 :        729 :     return (impl_->rrset_->getRRsig());
     596                 :            : }
     597                 :            : 
     598                 :            : void
     599                 :          1 : RBNodeRRset::addRRsig(const ConstRdataPtr& rdata) {
     600                 :          2 :     AbstractRRset* p = const_cast<AbstractRRset*>(impl_->rrset_.get());
     601                 :          1 :     p->addRRsig(rdata);
     602                 :          1 : }
     603                 :            : 
     604                 :            : void
     605                 :          1 : RBNodeRRset::addRRsig(const RdataPtr& rdata) {
     606                 :          2 :     AbstractRRset* p = const_cast<AbstractRRset*>(impl_->rrset_.get());
     607                 :          1 :     p->addRRsig(rdata);
     608                 :          1 : }
     609                 :            : 
     610                 :            : void
     611                 :          2 : RBNodeRRset::addRRsig(const AbstractRRset& sigs) {
     612                 :          4 :     AbstractRRset* p = const_cast<AbstractRRset*>(impl_->rrset_.get());
     613                 :          2 :     p->addRRsig(sigs);
     614                 :          2 : }
     615                 :            : 
     616                 :            : void
     617                 :        642 : RBNodeRRset::addRRsig(const ConstRRsetPtr& sigs) {
     618                 :       1284 :     AbstractRRset* p = const_cast<AbstractRRset*>(impl_->rrset_.get());
     619                 :        642 :     p->addRRsig(sigs);
     620                 :        642 : }
     621                 :            : 
     622                 :            : void
     623                 :          1 : RBNodeRRset::addRRsig(const RRsetPtr& sigs) {
     624                 :          2 :     AbstractRRset* p = const_cast<AbstractRRset*>(impl_->rrset_.get());
     625                 :          1 :     p->addRRsig(sigs);
     626                 :          1 : }
     627                 :            : 
     628                 :            : void
     629                 :          1 : RBNodeRRset::removeRRsig() {
     630                 :          2 :     AbstractRRset* p = const_cast<AbstractRRset*>(impl_->rrset_.get());
     631                 :          1 :     p->removeRRsig();
     632                 :          1 : }
     633                 :            : 
     634                 :            : ConstRRsetPtr
     635                 :         22 : RBNodeRRset::getUnderlyingRRset() const {
     636                 :         22 :     return (impl_->rrset_);
     637                 :            : }
     638                 :            : 
     639                 :            : void
     640                 :        423 : RBNodeRRset::addAdditionalNode(const AdditionalNodeInfo& additional) {
     641                 :            :     // Lazy initialization
     642         [ +  + ]:        423 :     if (!impl_->additionals_) {
     643                 :        240 :         impl_->additionals_.reset(new vector<AdditionalNodeInfo>);
     644                 :            :     }
     645                 :        423 :     impl_->additionals_->push_back(additional);
     646                 :        423 : }
     647                 :            : 
     648                 :            : const vector<AdditionalNodeInfo>*
     649                 :         33 : RBNodeRRset::getAdditionalNodes() const {
     650                 :         33 :     return (impl_->additionals_.get());
     651                 :            : }
     652                 :            : 
     653                 :            : void
     654                 :         51 : RBNodeRRset::copyAdditionalNodes(RBNodeRRset& dst) const {
     655         [ +  + ]:         51 :     if (impl_->additionals_) {
     656                 :            :         dst.impl_->additionals_.reset(
     657                 :          1 :             new vector<AdditionalNodeInfo>(impl_->additionals_->begin(),
     658                 :          2 :                                            impl_->additionals_->end()));
     659                 :            :     }
     660                 :         51 : }
     661                 :            : 
     662                 :            : } // end of internal
     663                 :            : 
     664                 :            : namespace {
     665                 :            : /*
     666                 :            :  * Prepares a rrset to be return as a result.
     667                 :            :  *
     668                 :            :  * If rename is false, it returns the one provided. If it is true, it
     669                 :            :  * creates a new rrset with the same data but with provided name.
     670                 :            :  * In addition, if DNSSEC records are required by the original caller of
     671                 :            :  * find(), it also creates expanded RRSIG based on the RRSIG of the
     672                 :            :  * wildcard RRset.
     673                 :            :  * It is designed for wildcard case, where we create the rrsets
     674                 :            :  * dynamically.
     675                 :            :  */
     676                 :            : ConstRBNodeRRsetPtr
     677                 :        154 : prepareRRset(const Name& name, const ConstRBNodeRRsetPtr& rrset, bool rename,
     678                 :            :              ZoneFinder::FindOptions options)
     679                 :            : {
     680         [ +  + ]:        154 :     if (rename) {
     681         [ +  - ]:        102 :         LOG_DEBUG(logger, DBG_TRACE_DETAILED, DATASRC_MEM_RENAME).
     682 [ +  - ][ +  - ]:         51 :             arg(rrset->getName()).arg(name);
     683                 :         51 :         RRsetPtr result_base(new RRset(name, rrset->getClass(),
     684         [ +  - ]:         51 :                                        rrset->getType(), rrset->getTTL()));
     685 [ +  - ][ +  - ]:        102 :         for (RdataIteratorPtr i(rrset->getRdataIterator()); !i->isLast();
                 [ +  + ]
     686         [ +  - ]:         51 :              i->next()) {
     687 [ +  - ][ +  - ]:         51 :             result_base->addRdata(i->getCurrent());
     688                 :            :         }
     689         [ +  + ]:         51 :         if ((options & ZoneFinder::FIND_DNSSEC) != 0) {
     690         [ +  - ]:         19 :             ConstRRsetPtr sig_rrset = rrset->getRRsig();
     691         [ +  + ]:         19 :             if (sig_rrset) {
     692                 :          6 :                 RRsetPtr result_sig(new RRset(name, sig_rrset->getClass(),
     693                 :            :                                               RRType::RRSIG(),
     694 [ +  - ][ +  - ]:          6 :                                               sig_rrset->getTTL()));
         [ +  - ][ +  - ]
                 [ +  - ]
     695 [ +  - ][ +  + ]:         18 :                 for (RdataIteratorPtr i(sig_rrset->getRdataIterator());
     696         [ +  - ]:         12 :                      !i->isLast();
     697         [ +  - ]:          6 :                      i->next())
     698                 :            :                 {
     699 [ +  - ][ +  - ]:          6 :                     result_sig->addRdata(i->getCurrent());
     700                 :            :                 }
     701         [ +  - ]:          6 :                 result_base->addRRsig(result_sig);
     702                 :            :             }
     703                 :            :         }
     704 [ +  - ][ +  - ]:         51 :         RBNodeRRsetPtr result(new RBNodeRRset(result_base));
     705         [ +  - ]:         51 :         rrset->copyAdditionalNodes(*result);
     706                 :            :         return (result);
     707                 :            :     } else {
     708                 :            :         return (rrset);
     709                 :            :     }
     710                 :            : }
     711                 :            : 
     712                 :            : // Specialized version of ZoneFinder::ResultContext, which specifically
     713                 :            : // holds rrset in the form of RBNodeRRset.
     714                 :        298 : struct RBNodeResultContext {
     715                 :            :     /// \brief Constructor
     716                 :            :     ///
     717                 :            :     /// The first three parameters correspond to those of
     718                 :            :     /// ZoneFinder::ResultContext.  If node is non NULL, it specifies the
     719                 :            :     /// found RBNode in the search.
     720                 :            :     RBNodeResultContext(ZoneFinder::Result code_param,
     721                 :            :                         ConstRBNodeRRsetPtr rrset_param,
     722                 :            :                         ZoneFinder::FindResultFlags flags_param,
     723                 :            :                         const DomainNode* node) :
     724                 :            :         code(code_param), rrset(rrset_param), flags(flags_param),
     725                 :        596 :         found_node(node)
     726                 :            :     {}
     727                 :            : 
     728                 :            :     const ZoneFinder::Result code;
     729                 :            :     const ConstRBNodeRRsetPtr rrset;
     730                 :            :     const ZoneFinder::FindResultFlags flags;
     731                 :            :     const DomainNode* const found_node;
     732                 :            : };
     733                 :            : }
     734                 :            : 
     735                 :        596 : class InMemoryZoneFinder::Context : public ZoneFinder::Context {
     736                 :            : public:
     737                 :            :     /// \brief Constructor.
     738                 :            :     ///
     739                 :            :     /// Note that we don't have a specific constructor for the findAll() case.
     740                 :            :     /// For (successful) type ANY query, found_node points to the
     741                 :            :     /// corresponding RB node, which is recorded within this specialized
     742                 :            :     /// context.
     743                 :        298 :     Context(ZoneFinder& finder, ZoneFinder::FindOptions options,
     744                 :            :             const RBNodeResultContext& result) :
     745                 :            :         ZoneFinder::Context(finder, options,
     746                 :            :                             ResultContext(result.code, result.rrset,
     747                 :            :                                           result.flags)),
     748                 :       1490 :         rrset_(result.rrset), found_node_(result.found_node)
     749                 :        298 :     {}
     750                 :            : 
     751                 :            : protected:
     752                 :         31 :     virtual void getAdditionalImpl(const vector<RRType>& requested_types,
     753                 :            :                                    vector<ConstRRsetPtr>& result)
     754                 :            :     {
     755         [ +  + ]:         31 :         if (!rrset_) {
     756                 :            :             // In this case this context should encapsulate the result of
     757                 :            :             // findAll() and found_node_ should point to a valid answer node.
     758 [ +  - ][ +  - ]:          1 :             if (found_node_ == NULL || found_node_->isEmpty()) {
                 [ -  + ]
     759         [ #  # ]:          0 :                 isc_throw(isc::Unexpected,
     760                 :            :                           "Invalid call to in-memory getAdditional: caller's "
     761                 :            :                           "bug or broken zone");
     762                 :            :             }
     763 [ +  + ][ +  - ]:          7 :             BOOST_FOREACH(const DomainPair& dom_it, *found_node_->getData()) {
         [ +  - ][ +  + ]
                 [ +  + ]
     764                 :          3 :                 getAdditionalForRRset(*dom_it.second, requested_types,
     765                 :          3 :                                       result);
     766                 :            :             }
     767                 :            :         } else {
     768                 :         30 :             getAdditionalForRRset(*rrset_, requested_types, result);
     769                 :            :         }
     770                 :         31 :     }
     771                 :            : 
     772                 :            : private:
     773                 :            :     // Retrieve additional RRsets for a given RRset associated in the context.
     774                 :            :     // The process is straightforward: it examines the link to
     775                 :            :     // AdditionalNodeInfo vector (if set), and find RRsets of the requested
     776                 :            :     // type for each node.
     777                 :         33 :     static void getAdditionalForRRset(const RBNodeRRset& rrset,
     778                 :            :                                       const vector<RRType>& requested_types,
     779                 :            :                                       vector<ConstRRsetPtr>& result)
     780                 :            :     {
     781                 :            :         const vector<AdditionalNodeInfo>* additionals_ =
     782                 :         33 :             rrset.getAdditionalNodes();
     783         [ +  + ]:         33 :         if (additionals_ == NULL) {
     784                 :         33 :             return;
     785                 :            :         }
     786                 :         28 :         const bool glue_ok = (rrset.getType() == RRType::NS());
     787 [ +  + ][ +  - ]:        146 :         BOOST_FOREACH(const AdditionalNodeInfo& additional, *additionals_) {
         [ +  - ][ +  + ]
                 [ +  + ]
     788         [ -  + ]:         59 :             assert(additional.node_ != NULL);
     789         [ +  + ]:         59 :             if (additional.node_->isEmpty()) {
     790                 :          1 :                 continue;
     791                 :            :             }
     792 [ +  + ][ +  + ]:         58 :             if (!glue_ok && additional.node_->getFlag(domain_flag::GLUE)) {
                 [ +  + ]
     793                 :          5 :                 continue;
     794                 :            :             }
     795                 :            :             const bool wild_expanded =
     796                 :        106 :                 additional.node_->getFlag(domain_flag::WILD_EXPANDED);
     797 [ +  + ][ +  - ]:        317 :             BOOST_FOREACH(const RRType& rrtype, requested_types) {
         [ +  - ][ +  + ]
                 [ +  + ]
     798                 :            :                 Domain::const_iterator found =
     799                 :         86 :                     additional.node_->getData()->find(rrtype);
     800         [ +  + ]:         86 :                 if (found != additional.node_->getData()->end()) {
     801                 :            :                     // If the additional node was generated as a result of
     802                 :            :                     // wildcard expansion, we return the underlying RRset,
     803                 :            :                     // in case the caller has the same RRset but as a result
     804                 :            :                     // of normal find() and needs to know they are of the same
     805                 :            :                     // kind; otherwise we simply use the stored RBNodeRRset.
     806         [ +  + ]:         51 :                     if (wild_expanded) {
     807         [ +  - ]:          1 :                         result.push_back(found->second->getUnderlyingRRset());
     808                 :            :                     } else {
     809         [ +  - ]:         50 :                         result.push_back(found->second);
     810                 :            :                     }
     811                 :            :                 }
     812                 :            :             }
     813                 :            :         }
     814                 :            :     }
     815                 :            : 
     816                 :            :     const ConstRBNodeRRsetPtr rrset_;
     817                 :            :     const DomainNode* const found_node_;
     818                 :            : };
     819                 :            : 
     820                 :            : // Private data and hidden methods of InMemoryZoneFinder
     821         [ +  - ]:        151 : struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
     822                 :            :     // Constructor
     823                 :            :     InMemoryZoneFinderImpl(const RRClass& zone_class, const Name& origin) :
     824                 :            :         zone_class_(zone_class), origin_(origin),
     825 [ +  - ][ +  - ]:        302 :         zone_data_(new ZoneData(origin_))
                 [ +  - ]
     826                 :            :     {}
     827                 :            : 
     828                 :            :     // Information about the zone
     829                 :            :     RRClass zone_class_;
     830                 :            :     Name origin_;
     831                 :            :     string file_name_;
     832                 :            : 
     833                 :            :     // The actual zone data
     834                 :            :     scoped_ptr<ZoneData> zone_data_;
     835                 :            : 
     836                 :            :     // Common process for zone load.
     837                 :            :     // rrset_installer is a functor that takes another functor as an argument,
     838                 :            :     // and expected to call the latter for each RRset of the zone.  How the
     839                 :            :     // sequence of the RRsets is generated depends on the internal
     840                 :            :     // details  of the loader: either from a textual master file or from
     841                 :            :     // another data source.
     842                 :            :     // filename is the file name of the master file or empty if the zone is
     843                 :            :     // loaded from another data source.
     844                 :            :     void load(const string& filename,
     845                 :            :               boost::function<void(LoadCallback)> rrset_installer);
     846                 :            : 
     847                 :            :     // Add the necessary magic for any wildcard contained in 'name'
     848                 :            :     // (including itself) to be found in the zone.
     849                 :            :     //
     850                 :            :     // In order for wildcard matching to work correctly in find(),
     851                 :            :     // we must ensure that a node for the wildcarding level exists in the
     852                 :            :     // backend RBTree.
     853                 :            :     // E.g. if the wildcard name is "*.sub.example." then we must ensure
     854                 :            :     // that "sub.example." exists and is marked as a wildcard level.
     855                 :            :     // Note: the "wildcarding level" is for the parent name of the wildcard
     856                 :            :     // name (such as "sub.example.").
     857                 :            :     //
     858                 :            :     // We also perform the same trick for empty wild card names possibly
     859                 :            :     // contained in 'name' (e.g., '*.foo.example' in 'bar.*.foo.example').
     860                 :       1051 :     void addWildcards(DomainTree& domains, const Name& name) {
     861                 :       2102 :         Name wname(name);
     862                 :       1051 :         const unsigned int labels(wname.getLabelCount());
     863                 :       1051 :         const unsigned int origin_labels(origin_.getLabelCount());
     864 [ +  - ][ +  + ]:       3687 :         for (unsigned int l = labels;
     865                 :            :              l > origin_labels;
     866         [ +  - ]:       2636 :              --l, wname = wname.split(1)) {
     867 [ +  - ][ +  + ]:       1318 :             if (wname.isWildcard()) {
     868 [ +  - ][ +  - ]:        168 :                 LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_ADD_WILDCARD).
                 [ +  - ]
     869 [ +  - ][ +  - ]:         84 :                     arg(name);
     870                 :            :                 // Ensure a separate level exists for the "wildcarding" name,
     871                 :            :                 // and mark the node as "wild".
     872                 :            :                 DomainNode* node;
     873                 :         84 :                 DomainTree::Result result(domains.insert(wname.split(1),
     874 [ +  - ][ +  - ]:         84 :                                                          &node));
     875                 :          0 :                 assert(result == DomainTree::SUCCESS ||
     876         [ -  + ]:         84 :                        result == DomainTree::ALREADYEXISTS);
     877         [ +  - ]:         84 :                 node->setFlag(domain_flag::WILD);
     878                 :            : 
     879                 :            :                 // Ensure a separate level exists for the wildcard name.
     880                 :            :                 // Note: for 'name' itself we do this later anyway, but the
     881                 :            :                 // overhead should be marginal because wildcard names should
     882                 :            :                 // be rare.
     883         [ +  - ]:         84 :                 result = domains.insert(wname, &node);
     884                 :          0 :                 assert(result == DomainTree::SUCCESS ||
     885         [ -  + ]:         84 :                        result == DomainTree::ALREADYEXISTS);
     886                 :            :             }
     887                 :            :         }
     888                 :       1051 :     }
     889                 :            : 
     890                 :            :     // A helper predicate used in contextCheck() to check if a given domain
     891                 :            :     // name has a RRset of type different than NSEC.
     892                 :          3 :     static bool isNotNSEC(const DomainPair& element) {
     893                 :          3 :         return (element.second->getType() != RRType::NSEC());
     894                 :            :     }
     895                 :            : 
     896                 :            :     /*
     897                 :            :      * Does some checks in context of the data that are already in the zone.
     898                 :            :      * Currently checks for forbidden combinations of RRsets in the same
     899                 :            :      * domain (CNAME+anything, DNAME+NS).
     900                 :            :      *
     901                 :            :      * If such condition is found, it throws AddError.
     902                 :            :      */
     903                 :       1051 :     void contextCheck(const AbstractRRset& rrset, const Domain& domain) const {
     904                 :            :         // Ensure CNAME and other type of RR don't coexist for the same
     905                 :            :         // owner name except with NSEC, which is the only RR that can coexist
     906                 :            :         // with CNAME (and also RRSIG, which is handled separately)
     907         [ +  + ]:       1051 :         if (rrset.getType() == RRType::CNAME()) {
     908         [ +  + ]:         25 :             if (find_if(domain.begin(), domain.end(), isNotNSEC)
     909                 :         50 :                 != domain.end()) {
     910         [ +  - ]:          4 :                 LOG_ERROR(logger, DATASRC_MEM_CNAME_TO_NONEMPTY).
     911         [ +  - ]:          2 :                     arg(rrset.getName());
     912 [ +  - ][ +  - ]:          4 :                 isc_throw(AddError, "CNAME can't be added with other data for "
         [ +  - ][ +  - ]
     913                 :            :                           << rrset.getName());
     914                 :            :             }
     915   [ +  +  +  + ]:       2025 :         } else if (rrset.getType() != RRType::NSEC() &&
                 [ +  + ]
     916                 :        999 :                    domain.find(RRType::CNAME()) != domain.end()) {
     917 [ +  - ][ +  - ]:          1 :             LOG_ERROR(logger, DATASRC_MEM_CNAME_COEXIST).arg(rrset.getName());
     918 [ +  - ][ +  - ]:          2 :             isc_throw(AddError, "CNAME and " << rrset.getType() <<
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
     919                 :            :                       " can't coexist for " << rrset.getName());
     920                 :            :         }
     921                 :            : 
     922                 :            :         /*
     923                 :            :          * Similar with DNAME, but it must not coexist only with NS and only in
     924                 :            :          * non-apex domains.
     925                 :            :          * RFC 2672 section 3 mentions that it is implied from it and RFC 2181
     926                 :            :          */
     927   [ +  +  +  +  :       3884 :         if (rrset.getName() != origin_ &&
          +  +  +  +  +  
              + ][ +  + ]
     928                 :            :             // Adding DNAME, NS already there
     929                 :        827 :             ((rrset.getType() == RRType::DNAME() &&
     930                 :         31 :             domain.find(RRType::NS()) != domain.end()) ||
     931                 :            :             // Adding NS, DNAME already there
     932                 :        826 :             (rrset.getType() == RRType::NS() &&
     933                 :        104 :             domain.find(RRType::DNAME()) != domain.end())))
     934                 :            :         {
     935 [ +  - ][ +  - ]:          2 :             LOG_ERROR(logger, DATASRC_MEM_DNAME_NS).arg(rrset.getName());
     936 [ +  - ][ +  - ]:          4 :             isc_throw(AddError, "DNAME can't coexist with NS in non-apex "
         [ +  - ][ +  - ]
     937                 :            :                 "domain " << rrset.getName());
     938                 :            :         }
     939                 :       1046 :     }
     940                 :            : 
     941                 :            :     // Validate rrset before adding it to the zone.  If something is wrong
     942                 :            :     // it throws an exception.  It doesn't modify the zone, and provides
     943                 :            :     // the strong exception guarantee.
     944                 :       1737 :     void addValidation(const ConstRRsetPtr rrset) {
     945         [ +  + ]:       1737 :         if (!rrset) {
     946         [ +  - ]:          2 :             isc_throw(NullRRset, "The rrset provided is NULL");
     947                 :            :         }
     948         [ +  + ]:       1736 :         if (rrset->getRdataCount() == 0) {
     949 [ +  - ][ +  - ]:          2 :             isc_throw(AddError, "The rrset provided is empty: " <<
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
     950                 :            :                       rrset->getName() << "/" << rrset->getType());
     951                 :            :         }
     952                 :            :         // Check for singleton RRs. It should probably handled at a different
     953                 :            :         // layer in future.
     954   [ +  +  +  +  :       3505 :         if ((rrset->getType() == RRType::CNAME() ||
           +  + ][ +  + ]
     955                 :       1709 :             rrset->getType() == RRType::DNAME()) &&
     956                 :         61 :             rrset->getRdataCount() > 1)
     957                 :            :         {
     958                 :            :             // XXX: this is not only for CNAME or DNAME. We should generalize
     959                 :            :             // this code for all other "singleton RR types" (such as SOA) in a
     960                 :            :             // separate task.
     961   [ +  -  +  - ]:          6 :             LOG_ERROR(logger, DATASRC_MEM_SINGLETON).arg(rrset->getName()).
     962         [ +  - ]:          4 :                 arg(rrset->getType());
     963 [ +  - ][ +  - ]:          4 :             isc_throw(AddError, "multiple RRs of singleton type for "
         [ +  - ][ +  - ]
     964                 :            :                       << rrset->getName());
     965                 :            :         }
     966                 :            :         // NSEC3/NSEC3PARAM is not a "singleton" per protocol, but this
     967                 :            :         // implementation requests it be so at the moment.
     968   [ +  +  +  +  :       3489 :         if ((rrset->getType() == RRType::NSEC3() ||
           +  + ][ +  + ]
     969                 :       1532 :              rrset->getType() == RRType::NSEC3PARAM()) &&
     970                 :        224 :             rrset->getRdataCount() > 1) {
     971 [ +  - ][ +  - ]:          4 :             isc_throw(AddError, "Multiple NSEC3/NSEC3PARAM RDATA is given for "
         [ +  - ][ +  - ]
                 [ +  - ]
     972                 :            :                       << rrset->getName() << " which isn't supported");
     973                 :            :         }
     974                 :            : 
     975                 :       1731 :         NameComparisonResult compare(origin_.compare(rrset->getName()));
     976 [ +  + ][ +  + ]:       1731 :         if (compare.getRelation() != NameComparisonResult::SUPERDOMAIN &&
                 [ +  + ]
     977                 :            :             compare.getRelation() != NameComparisonResult::EQUAL)
     978                 :            :         {
     979 [ +  - ][ +  - ]:          2 :             LOG_ERROR(logger, DATASRC_MEM_OUT_OF_ZONE).arg(rrset->getName()).
     980         [ +  - ]:          1 :                 arg(origin_);
     981 [ +  - ][ +  - ]:          2 :             isc_throw(OutOfZone, "The name " << rrset->getName() <<
         [ +  - ][ +  - ]
                 [ +  - ]
     982                 :            :                 " is not contained in zone " << origin_);
     983                 :            :         }
     984                 :            : 
     985                 :            :         // Some RR types do not really work well with a wildcard.
     986                 :            :         // Even though the protocol specifically doesn't completely ban such
     987                 :            :         // usage, we refuse to load a zone containing such RR in order to
     988                 :            :         // keep the lookup logic simpler and more predictable.
     989                 :            :         // See RFC4592 and (for DNAME) draft-ietf-dnsext-rfc2672bis-dname
     990                 :            :         // for more technical background.  Note also that BIND 9 refuses
     991                 :            :         // NS at a wildcard, so in that sense we simply provide compatible
     992                 :            :         // behavior.
     993         [ +  + ]:       1730 :         if (rrset->getName().isWildcard()) {
     994         [ +  + ]:         76 :             if (rrset->getType() == RRType::NS()) {
     995         [ +  - ]:          2 :                 LOG_ERROR(logger, DATASRC_MEM_WILDCARD_NS).
     996         [ +  - ]:          1 :                     arg(rrset->getName());
     997 [ +  - ][ +  - ]:          2 :                 isc_throw(AddError, "Invalid NS owner name (wildcard): " <<
         [ +  - ][ +  - ]
     998                 :            :                           rrset->getName());
     999                 :            :             }
    1000         [ +  + ]:         75 :             if (rrset->getType() == RRType::DNAME()) {
    1001         [ +  - ]:          2 :                 LOG_ERROR(logger, DATASRC_MEM_WILDCARD_DNAME).
    1002         [ +  - ]:          1 :                     arg(rrset->getName());
    1003 [ +  - ][ +  - ]:          2 :                 isc_throw(AddError, "Invalid DNAME owner name (wildcard): " <<
         [ +  - ][ +  - ]
    1004                 :            :                           rrset->getName());
    1005                 :            :             }
    1006                 :            :         }
    1007                 :            : 
    1008                 :            :         // Owner names of NSEC3 have special format as defined in RFC5155,
    1009                 :            :         // and cannot be a wildcard name or must be one label longer than
    1010                 :            :         // the zone origin.  While the RFC doesn't prohibit other forms of
    1011                 :            :         // names, no sane zone would have such names for NSEC3.
    1012                 :            :         // BIND 9 also refuses NSEC3 at wildcard.
    1013   [ +  +  +  +  :       2127 :         if (rrset->getType() == RRType::NSEC3() &&
           +  + ][ +  + ]
    1014                 :        200 :             (rrset->getName().isWildcard() ||
    1015                 :        199 :              rrset->getName().getLabelCount() !=
    1016                 :            :              origin_.getLabelCount() + 1)) {
    1017         [ +  - ]:          4 :             LOG_ERROR(logger, DATASRC_BAD_NSEC3_NAME).
    1018         [ +  - ]:          2 :                 arg(rrset->getName());
    1019 [ +  - ][ +  - ]:          4 :             isc_throw(AddError, "Invalid NSEC3 owner name: " <<
         [ +  - ][ +  - ]
    1020                 :            :                       rrset->getName());
    1021                 :            :         }
    1022                 :       1726 :     }
    1023                 :            : 
    1024                 :        477 :     result::Result addRRsig(const ConstRRsetPtr sig_rrset, ZoneData& zone_data)
    1025                 :            :     {
    1026                 :            :         // Check consistency of the type covered.
    1027                 :            :         // We know the RRset isn't empty, so the following check is safe.
    1028                 :        477 :         RdataIteratorPtr rit = sig_rrset->getRdataIterator();
    1029                 :            :         const RRType covered = dynamic_cast<const generic::RRSIG&>(
    1030 [ +  - ][ +  - ]:        477 :             rit->getCurrent()).typeCovered();
         [ +  - ][ #  # ]
         [ #  # ][ #  # ]
    1031 [ +  - ][ +  - ]:        478 :         for (rit->next(); !rit->isLast(); rit->next()) {
         [ +  - ][ +  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1032 [ +  + ][ #  # ]:          2 :             if (dynamic_cast<const generic::RRSIG&>(
    1033 [ +  - ][ +  - ]:          2 :                     rit->getCurrent()).typeCovered() != covered) {
         [ +  - ][ #  # ]
         [ #  # ][ #  # ]
    1034 [ +  - ][ +  - ]:          2 :                 isc_throw(AddError, "RRSIG contains mixed covered types: "
         [ +  - ][ +  - ]
         [ +  - ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1035                 :            :                           << sig_rrset->toText());
    1036                 :            :             }
    1037                 :            :         }
    1038                 :            : 
    1039                 :            :         // Find the RRset to be covered; if not found, treat it as an error
    1040                 :            :         // for now.
    1041                 :            :         ConstRRsetPtr covered_rrset;
    1042 [ +  + ][ #  # ]:        476 :         if (covered != RRType::NSEC3()) {
    1043                 :        299 :             DomainNode* node = NULL;
    1044 [ +  - ][ +  - ]:        299 :             if (zone_data.domains_.find(sig_rrset->getName(), &node) !=
         [ +  + ][ +  - ]
         [ +  + ][ +  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1045                 :        298 :                 DomainTree::EXACTMATCH || node == NULL || !node->getData()) {
    1046 [ +  - ][ +  - ]:          4 :                 isc_throw(AddError,
         [ +  - ][ +  - ]
         [ +  - ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1047                 :            :                           "RRSIG is being added, but no RR to be covered: "
    1048                 :            :                           << sig_rrset->getName());
    1049                 :            :             }
    1050                 :        297 :             const Domain::const_iterator it = node->getData()->find(covered);
    1051   [ +  +  #  # ]:        297 :             if (it != node->getData()->end()) {
    1052 [ +  - ][ #  # ]:        296 :                 covered_rrset = it->second;
    1053                 :            :             }
    1054                 :            :         } else {
    1055                 :            :             // In case of NSEC3 if something is found it must be NSEC3 RRset
    1056                 :            :             // under the assumption of our current implementation.
    1057 [ +  + ][ #  # ]:        177 :             if (zone_data.nsec3_data_) {
    1058                 :            :                 // Convert the first label to upper-cased text.  Note that
    1059                 :            :                 // for a valid NSEC3 RR the label should only consist of
    1060                 :            :                 // positive 8-bit char values, so using toupper(int) should be
    1061                 :            :                 // safe (if it's a bogus label for NSEC3 the zone won't work
    1062                 :            :                 // anyway).  Also note the '::' below: g++'s STL implementation
    1063                 :            :                 // seems to require it to toupper to make this compile.
    1064                 :            :                 string fst_label =
    1065 [ +  - ][ +  - ]:        352 :                     sig_rrset->getName().split(0, 1).toText(true);
         [ +  - ][ #  # ]
         [ #  # ][ #  # ]
    1066                 :            :                 transform(fst_label.begin(), fst_label.end(),
    1067 [ +  - ][ #  # ]:        176 :                           fst_label.begin(), ::toupper);
    1068                 :            : 
    1069                 :            :                 NSEC3Map::const_iterator found =
    1070                 :        176 :                     zone_data.nsec3_data_->map_.find(fst_label);
    1071   [ +  +  #  # ]:        176 :                 if (found != zone_data.nsec3_data_->map_.end()) {
    1072 [ +  - ][ #  # ]:        175 :                     covered_rrset = found->second;
    1073 [ +  - ][ -  + ]:        175 :                     assert(covered_rrset->getType() == covered);
         [ #  # ][ #  # ]
    1074                 :            :                 }
    1075                 :            :             }
    1076                 :            :         }
    1077 [ +  + ][ #  # ]:        474 :         if (!covered_rrset) {
    1078 [ +  - ][ +  - ]:          6 :             isc_throw(AddError, "RRSIG is being added, but no RR of "
         [ +  - ][ +  - ]
         [ +  - ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1079                 :            :                       "covered type found: " << sig_rrset->toText());
    1080                 :            :         }
    1081                 :            : 
    1082                 :            :         // The current implementation doesn't allow an existing RRSIG to be
    1083                 :            :         // overridden (or updated with additional ones).
    1084 [ +  - ][ +  + ]:        942 :         if (covered_rrset->getRRsig()) {
         [ #  # ][ #  # ]
    1085 [ +  - ][ +  - ]:          6 :             isc_throw(AddError,
         [ +  - ][ +  - ]
         [ +  - ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1086                 :            :                       "RRSIG is being added to override an existing one: "
    1087                 :            :                       << sig_rrset->toText());
    1088                 :            :         }
    1089                 :            : 
    1090                 :            :         // All okay, setting the RRSIG.
    1091                 :            :         // XXX: we break const-ness of the covered RRsets.  In practice the
    1092                 :            :         // ownership of these RRsets would have been given to us so it should
    1093                 :            :         // be safe, but it's still a very bad practice.
    1094                 :            :         // We'll fix this problem anyway when we update the underlying
    1095                 :            :         // representation so that it's more space efficient.
    1096                 :            :         // Note: there's a slight chance of getting an exception.
    1097                 :            :         // As noted in add(), we give up strong exception guarantee in such
    1098                 :            :         // cases.
    1099 [ +  - ][ #  # ]:        468 :         boost::const_pointer_cast<AbstractRRset>(covered_rrset)->addRRsig(sig_rrset);
    1100                 :            : 
    1101                 :        468 :         return (result::SUCCESS);
    1102                 :            :     }
    1103                 :            : 
    1104                 :          0 :     result::Result addNSEC3(const ConstRRsetPtr rrset, ZoneData& zone_data) {
    1105                 :            :         // We know rrset has exactly one RDATA
    1106                 :            :         const generic::NSEC3& nsec3_rdata =
    1107                 :            :             dynamic_cast<const generic::NSEC3&>(
    1108 [ +  - ][ +  - ]:        198 :                 rrset->getRdataIterator()->getCurrent());
         [ +  - ][ #  # ]
                 [ #  # ]
    1109                 :            : 
    1110                 :            :         // If we've not done any NSEC3 setup for the zone, do it now;
    1111                 :            :         // otherwise check parameter consistency.
    1112   [ +  +  #  # ]:        198 :         if (!zone_data.nsec3_data_) {
    1113 [ +  - ][ +  - ]:         30 :             zone_data.nsec3_data_.reset(new ZoneData::NSEC3Data(nsec3_rdata));
    1114 [ +  - ][ +  + ]:        366 :         } else if (!zone_data.nsec3_data_->hash_->match(nsec3_rdata)) {
                 [ #  # ]
    1115 [ +  - ][ +  - ]:          4 :             isc_throw(AddError, "NSEC3 with inconsistent parameters: " <<
         [ +  - ][ +  - ]
         [ +  - ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1116                 :            :                       rrset->toText());
    1117                 :            :         }
    1118                 :            : 
    1119 [ +  - ][ +  - ]:        392 :         string fst_label = rrset->getName().split(0, 1).toText(true);
         [ +  - ][ #  # ]
    1120                 :            :         transform(fst_label.begin(), fst_label.end(), fst_label.begin(),
    1121 [ +  - ][ #  # ]:        196 :                   ::toupper);
    1122                 :            : 
    1123                 :            :         // Our current implementation doesn't allow an existing NSEC3 to be
    1124                 :            :         // updated/overridden.
    1125   [ +  +  #  # ]:        392 :         if (zone_data.nsec3_data_->map_.find(fst_label) !=
    1126                 :        392 :             zone_data.nsec3_data_->map_.end()) {
    1127                 :            :             return (result::EXIST);
    1128                 :            :         }
    1129                 :            : 
    1130                 :        195 :         zone_data.nsec3_data_->map_.insert(
    1131 [ +  - ][ +  - ]:        390 :             NSEC3Pair(fst_label, ConstRBNodeRRsetPtr(new RBNodeRRset(rrset))));
         [ +  - ][ #  # ]
         [ #  # ][ #  # ]
    1132                 :            :         return (result::SUCCESS);
    1133                 :            :     }
    1134                 :            : 
    1135                 :            :     /*
    1136                 :            :      * Implementation of longer methods. We put them here, because the
    1137                 :            :      * access is without the impl_-> and it will get inlined anyway.
    1138                 :            :      */
    1139                 :            :     // Implementation of InMemoryZoneFinder::add
    1140                 :       1737 :     result::Result add(const ConstRRsetPtr& rawrrset, ZoneData& zone_data,
    1141                 :            :                        vector<RBNodeRRset*>* need_additionals)
    1142                 :            :     {
    1143                 :            :         // Sanitize input.  This will cause an exception to be thrown
    1144                 :            :         // if the input RRset is empty.
    1145         [ +  + ]:       1737 :         addValidation(rawrrset);
    1146                 :            : 
    1147                 :            :         // OK, can add the RRset.
    1148         [ +  - ]:       3452 :         LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_ADD_RRSET).
    1149 [ +  - ][ +  - ]:       1726 :             arg(rawrrset->getName()).arg(rawrrset->getType()).arg(origin_);
                 [ +  - ]
    1150                 :            : 
    1151                 :            :         // ... although instead of loading the RRset directly, we encapsulate
    1152                 :            :         // it within an RBNodeRRset.  This contains additional information that
    1153                 :            :         // speeds up queries.
    1154         [ +  - ]:       1726 :         RBNodeRRsetPtr rrset(new RBNodeRRset(rawrrset));
    1155                 :            : 
    1156 [ +  - ][ +  + ]:       1726 :         if (rrset->getType() == RRType::NSEC3()) {
    1157                 :        196 :             return (addNSEC3(rrset, zone_data));
    1158                 :            :         }
    1159                 :            : 
    1160                 :            :         // RRSIGs are special in various points, so we handle it in a
    1161                 :            :         // separate dedicated method.
    1162 [ +  - ][ +  + ]:       1528 :         if (rrset->getType() == RRType::RRSIG()) {
    1163         [ +  + ]:        477 :             return (addRRsig(rrset, zone_data));
    1164                 :            :         }
    1165                 :            : 
    1166                 :            :         // Add wildcards possibly contained in the owner name to the domain
    1167                 :            :         // tree.
    1168                 :            :         // Note: this can throw an exception, breaking strong exception
    1169                 :            :         // guarantee.  (see also the note for contextCheck() below).
    1170 [ +  - ][ +  - ]:       1051 :         addWildcards(zone_data.domains_, rrset->getName());
    1171                 :            : 
    1172                 :            :         // Get the node
    1173                 :            :         DomainNode* node;
    1174         [ +  - ]:       1051 :         DomainTree::Result result = zone_data.domains_.insert(rrset->getName(),
    1175         [ +  - ]:       1051 :                                                               &node);
    1176                 :            :         // Just check it returns reasonable results
    1177                 :          0 :         assert((result == DomainTree::SUCCESS ||
    1178 [ +  - ][ -  + ]:       1051 :                 result == DomainTree::ALREADYEXISTS) && node!= NULL);
    1179                 :            : 
    1180                 :            :         // Now get the domain
    1181                 :            :         DomainPtr domain;
    1182                 :            :         // It didn't exist yet, create it
    1183         [ +  + ]:       1051 :         if (node->isEmpty()) {
    1184         [ +  - ]:        652 :             domain.reset(new Domain);
    1185                 :        652 :             node->setData(domain);
    1186                 :            :         } else { // Get existing one
    1187         [ +  - ]:        399 :             domain = node->getData();
    1188                 :            :         }
    1189                 :            : 
    1190                 :            :         // Checks related to the surrounding data.
    1191                 :            :         // Note: when the check fails and the exception is thrown, it may
    1192                 :            :         // break strong exception guarantee.  At the moment we prefer
    1193                 :            :         // code simplicity and don't bother to introduce complicated
    1194                 :            :         // recovery code.
    1195         [ +  + ]:       1051 :         contextCheck(*rrset, *domain);
    1196                 :            : 
    1197                 :            :         // Try inserting the rrset there
    1198 [ +  - ][ +  + ]:       3138 :         if (domain->insert(DomainPair(rrset->getType(), rrset)).second) {
    1199                 :            :             // Ok, we just put it in
    1200                 :            : 
    1201                 :            :             // If this RRset creates a zone cut at this node, mark the node
    1202                 :            :             // indicating the need for callback in find().
    1203 [ +  - ][ +  + ]:       1213 :             if (rrset->getType() == RRType::NS() &&
         [ +  + ][ +  + ]
    1204         [ +  - ]:        171 :                 rrset->getName() != origin_) {
    1205         [ +  - ]:        103 :                 node->setFlag(DomainNode::FLAG_CALLBACK);
    1206                 :            :                 // If it is DNAME, we have a callback as well here
    1207 [ +  - ][ +  + ]:        939 :             } else if (rrset->getType() == RRType::DNAME()) {
    1208         [ +  - ]:         32 :                 node->setFlag(DomainNode::FLAG_CALLBACK);
    1209                 :            :             }
    1210                 :            : 
    1211 [ +  + ][ +  + ]:       2655 :             if (need_additionals != NULL &&
         [ +  + ][ +  + ]
    1212         [ +  - ]:        880 :                 (rrset->getType() == RRType::NS() ||
    1213         [ +  - ]:        733 :                  rrset->getType() == RRType::MX())) {
    1214         [ +  - ]:        243 :                 need_additionals->push_back(rrset.get());
    1215                 :            :             }
    1216                 :            : 
    1217                 :            :             // If we've added NSEC3PARAM at zone origin, set up NSEC3 specific
    1218                 :            :             // data or check consistency with already set up parameters.
    1219 [ +  - ][ +  + ]:       1064 :             if (rrset->getType() == RRType::NSEC3PARAM() &&
         [ +  + ][ +  + ]
    1220         [ +  - ]:         22 :                 rrset->getName() == origin_) {
    1221                 :            :                 // We know rrset has exactly one RDATA
    1222                 :            :                 const generic::NSEC3PARAM& param =
    1223                 :            :                     dynamic_cast<const generic::NSEC3PARAM&>(
    1224 [ +  - ][ +  - ]:         21 :                         rrset->getRdataIterator()->getCurrent());
                 [ +  - ]
    1225                 :            : 
    1226         [ +  + ]:         21 :                 if (!zone_data.nsec3_data_) {
    1227                 :            :                     zone_data.nsec3_data_.reset(
    1228 [ +  - ][ +  - ]:         40 :                         new ZoneData::NSEC3Data(param));
    1229 [ +  - ][ +  - ]:          2 :                 } else if (!zone_data.nsec3_data_->hash_->match(param)) {
    1230 [ +  - ][ +  - ]:          2 :                     isc_throw(AddError, "NSEC3PARAM with inconsistent "
         [ +  - ][ +  - ]
                 [ +  - ]
    1231                 :            :                               "parameters: " << rrset->toText());
    1232                 :            :                 }
    1233 [ +  - ][ +  + ]:       1021 :             } else if (rrset->getType() == RRType::NSEC()) {
    1234                 :            :                 // If it is NSEC signed zone, so we put a flag there
    1235                 :            :                 // (flag is enough)
    1236                 :         27 :                 zone_data.nsec_signed_ = true;
    1237                 :            :             }
    1238                 :            :             return (result::SUCCESS);
    1239                 :            :         } else {
    1240                 :            :             // The RRSet of given type was already there
    1241                 :            :             return (result::EXIST);
    1242                 :            :         }
    1243                 :            :     }
    1244                 :            : 
    1245                 :            :     /*
    1246                 :            :      * Same as above, but it checks the return value and if it already exists,
    1247                 :            :      * it throws.
    1248                 :            :      */
    1249                 :       1516 :     void addFromLoad(const ConstRRsetPtr& set, ZoneData* zone_data,
    1250                 :            :                      vector<RBNodeRRset*>* need_additionals)
    1251                 :            :     {
    1252      [ +  -  + ]:       1516 :         switch (add(set, *zone_data, need_additionals)) {
    1253                 :            :         case result::EXIST:
    1254         [ +  - ]:          4 :             LOG_ERROR(logger, DATASRC_MEM_DUP_RRSET).
    1255 [ +  - ][ +  - ]:          2 :                 arg(set->getName()).arg(set->getType());
    1256 [ +  - ][ +  - ]:          4 :             isc_throw(dns::MasterLoadError, "Duplicate rrset: " <<
                 [ +  - ]
    1257                 :            :                       set->toText());
    1258                 :            :         case result::SUCCESS:
    1259                 :       1514 :             return;
    1260                 :            :         default:
    1261                 :          0 :             assert(0);
    1262                 :            :         }
    1263                 :            :     }
    1264                 :            : 
    1265                 :            :     // A helper function for the NXRRSET case in find().  If the zone is
    1266                 :            :     // NSEC-signed and DNSSEC records are requested, try to find NSEC
    1267                 :            :     // on the given node, and return it if found; return NULL for all other
    1268                 :            :     // cases.
    1269                 :            :     ConstRBNodeRRsetPtr getNSECForNXRRSET(FindOptions options,
    1270                 :            :                                           const DomainNode& node) const
    1271                 :            :     {
    1272 [ +  + ][ +  + ]:         32 :         if (zone_data_->nsec_signed_ &&
                 [ +  + ]
    1273                 :            :             (options & ZoneFinder::FIND_DNSSEC) != 0) {
    1274                 :            :             const Domain::const_iterator found =
    1275                 :          3 :                 node.getData()->find(RRType::NSEC());
    1276         [ +  - ]:          3 :             if (found != node.getData()->end()) {
    1277                 :          3 :                 return (found->second);
    1278                 :            :             }
    1279                 :            :         }
    1280                 :            :         return (ConstRBNodeRRsetPtr());
    1281                 :            :     }
    1282                 :            : 
    1283                 :            :     // Set up FindContext object as a return value of find(), taking into
    1284                 :            :     // account wildcard matches and DNSSEC information.  We set the NSEC/NSEC3
    1285                 :            :     // flag when applicable regardless of the find option; the caller would
    1286                 :            :     // simply ignore these when they didn't request DNSSEC related results.
    1287                 :            :     // When the optional parameter 'node' is given (in which case it should be
    1288                 :            :     // non NULL), it means it's a result of ANY query and the context should
    1289                 :            :     // remember the matched node.
    1290                 :        298 :     RBNodeResultContext createFindResult(Result code,
    1291                 :            :                                          ConstRBNodeRRsetPtr rrset,
    1292                 :            :                                          bool wild = false,
    1293                 :            :                                          const DomainNode* node = NULL) const
    1294                 :            :     {
    1295                 :        298 :         FindResultFlags flags = RESULT_DEFAULT;
    1296         [ +  + ]:        298 :         if (wild) {
    1297                 :         57 :             flags = flags | RESULT_WILDCARD;
    1298                 :            :         }
    1299 [ +  + ][ +  + ]:        298 :         if (code == NXRRSET || code == NXDOMAIN || wild) {
    1300         [ +  + ]:        356 :             if (zone_data_->nsec3_data_) {
    1301                 :         43 :                 flags = flags | RESULT_NSEC3_SIGNED;
    1302                 :            :             }
    1303         [ +  + ]:        178 :             if (zone_data_->nsec_signed_) {
    1304                 :         59 :                 flags = flags | RESULT_NSEC_SIGNED;
    1305                 :            :             }
    1306                 :            :         }
    1307                 :        298 :         return (RBNodeResultContext(code, rrset, flags, node));
    1308                 :            :     }
    1309                 :            : 
    1310                 :            :     // Implementation of InMemoryZoneFinder::find
    1311                 :        309 :     RBNodeResultContext find(const Name& name, RRType type,
    1312                 :            :                              std::vector<ConstRRsetPtr>* target,
    1313                 :            :                              const FindOptions options) const
    1314                 :            :     {
    1315 [ +  - ][ +  - ]:        618 :         LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_FIND).arg(name).
    1316         [ +  - ]:        309 :             arg(type);
    1317                 :            : 
    1318                 :            :         // Get the node.  All other cases than an exact match are handled
    1319                 :            :         // in findNode().  We simply construct a result structure and return.
    1320                 :            :         RBTreeNodeChain<Domain> node_path; // findNode will fill in this
    1321                 :            :         const ZoneData::FindNodeResult node_result =
    1322                 :            :             zone_data_->findNode<ZoneData::FindNodeResult>(name, node_path,
    1323                 :        309 :                                                            options);
    1324         [ +  + ]:        298 :         if (node_result.code != SUCCESS) {
    1325         [ +  - ]:         79 :             return (createFindResult(node_result.code, node_result.rrset));
    1326                 :            :         }
    1327                 :            : 
    1328                 :            :         // We've found an exact match, may or may not be a result of wildcard.
    1329                 :        219 :         const DomainNode* node = node_result.node;
    1330         [ -  + ]:        219 :         assert(node != NULL);
    1331                 :            :         const bool rename = ((node_result.flags &
    1332                 :        219 :                               ZoneData::FindNodeResult::FIND_WILDCARD) != 0);
    1333                 :            : 
    1334                 :            :         // If there is an exact match but the node is empty, it's equivalent
    1335                 :            :         // to NXRRSET.
    1336         [ +  + ]:        219 :         if (node->isEmpty()) {
    1337 [ +  - ][ +  - ]:         98 :             LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_DOMAIN_EMPTY).
                 [ +  - ]
    1338 [ +  - ][ +  - ]:         49 :                 arg(name);
    1339                 :            :             return (createFindResult(NXRRSET,
    1340                 :            :                                      zone_data_->getClosestNSEC(node_path,
    1341                 :            :                                                                 options),
    1342 [ +  - ][ +  - ]:         49 :                                      rename));
    1343                 :            :         }
    1344                 :            : 
    1345                 :            :         Domain::const_iterator found;
    1346                 :            : 
    1347                 :            :         // If the node callback is enabled, this may be a zone cut.  If it
    1348                 :            :         // has a NS RR, we should return a delegation, but not in the apex.
    1349                 :            :         // There is one exception: the case for DS query, which should always
    1350                 :            :         // be considered in-zone lookup.
    1351   [ +  +  +  + ]:        187 :         if (node->getFlag(DomainNode::FLAG_CALLBACK) &&
         [ +  + ][ +  + ]
    1352                 :          9 :             node != zone_data_->origin_data_ && type != RRType::DS()) {
    1353                 :          7 :             found = node->getData()->find(RRType::NS());
    1354         [ +  + ]:          7 :             if (found != node->getData()->end()) {
    1355 [ +  - ][ +  - ]:          8 :                 LOG_DEBUG(logger, DBG_TRACE_DATA,
                 [ +  - ]
    1356 [ +  - ][ +  - ]:          4 :                           DATASRC_MEM_EXACT_DELEGATION).arg(name);
    1357                 :            :                 return (createFindResult(DELEGATION,
    1358                 :            :                                          prepareRRset(name, found->second,
    1359 [ +  - ][ +  - ]:          4 :                                                       rename, options)));
    1360                 :            :             }
    1361                 :            :         }
    1362                 :            : 
    1363                 :            :         // handle type any query
    1364 [ +  + ][ -  + ]:        166 :         if (target != NULL && !node->getData()->empty()) {
                 [ +  + ]
    1365                 :            :             // Empty domain will be handled as NXRRSET by normal processing
    1366         [ +  + ]:         30 :             for (found = node->getData()->begin();
    1367                 :         21 :                  found != node->getData()->end(); ++found)
    1368                 :            :             {
    1369                 :            :                 target->push_back(prepareRRset(name, found->second, rename,
    1370 [ +  - ][ +  - ]:         24 :                                                options));
    1371                 :            :             }
    1372 [ +  - ][ +  - ]:         18 :             LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_ANY_SUCCESS).
                 [ +  - ]
    1373 [ +  - ][ +  - ]:          9 :                 arg(name);
    1374                 :            :             return (createFindResult(SUCCESS, ConstRBNodeRRsetPtr(), rename,
    1375         [ +  - ]:          9 :                                      node));
    1376                 :            :         }
    1377                 :            : 
    1378                 :        157 :         found = node->getData()->find(type);
    1379         [ +  + ]:        157 :         if (found != node->getData()->end()) {
    1380                 :            :             // Good, it is here
    1381 [ +  - ][ +  - ]:        238 :             LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_SUCCESS).arg(name).
         [ +  - ][ +  - ]
                 [ +  - ]
    1382         [ +  - ]:        119 :                 arg(type);
    1383                 :            :             return (createFindResult(SUCCESS, prepareRRset(name,
    1384                 :            :                                                            found->second,
    1385                 :            :                                                            rename, options),
    1386 [ +  - ][ +  - ]:        119 :                                      rename));
    1387                 :            :         } else {
    1388                 :            :             // Next, try CNAME.
    1389                 :         38 :             found = node->getData()->find(RRType::CNAME());
    1390         [ +  + ]:         38 :             if (found != node->getData()->end()) {
    1391 [ +  - ][ +  - ]:          6 :                 LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_CNAME).arg(name);
         [ +  - ][ +  - ]
                 [ +  - ]
    1392                 :            :                 return (createFindResult(CNAME,
    1393                 :            :                                           prepareRRset(name, found->second,
    1394                 :            :                                                        rename, options),
    1395 [ +  - ][ +  - ]:          6 :                                           rename));
    1396                 :            :             }
    1397                 :            :         }
    1398                 :            :         // No exact match or CNAME.  Get NSEC if necessary and return NXRRSET.
    1399                 :            :         return (createFindResult(NXRRSET, getNSECForNXRRSET(options, *node),
    1400         [ +  - ]:         32 :                                  rename));
    1401                 :            :     }
    1402                 :            : };
    1403                 :            : 
    1404                 :        151 : InMemoryZoneFinder::InMemoryZoneFinder(const RRClass& zone_class,
    1405                 :            :                                        const Name& origin) :
    1406         [ +  - ]:        151 :     impl_(new InMemoryZoneFinderImpl(zone_class, origin))
    1407                 :            : {
    1408 [ +  - ][ +  - ]:        302 :     LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_CREATE).arg(origin).
         [ +  - ][ +  - ]
                 [ +  - ]
    1409         [ +  - ]:        151 :         arg(zone_class);
    1410                 :        151 : }
    1411                 :            : 
    1412                 :        224 : InMemoryZoneFinder::~InMemoryZoneFinder() {
    1413 [ +  - ][ +  - ]:        453 :     LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_DESTROY).arg(getOrigin()).
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
    1414 [ +  - ][ +  - ]:        302 :         arg(getClass());
    1415         [ +  - ]:        302 :     delete impl_;
    1416                 :        224 : }
    1417                 :            : 
    1418                 :            : Name
    1419                 :        438 : InMemoryZoneFinder::getOrigin() const {
    1420                 :        438 :     return (impl_->origin_);
    1421                 :            : }
    1422                 :            : 
    1423                 :            : RRClass
    1424                 :        290 : InMemoryZoneFinder::getClass() const {
    1425                 :        290 :     return (impl_->zone_class_);
    1426                 :            : }
    1427                 :            : 
    1428                 :            : ZoneFinderContextPtr
    1429                 :        286 : InMemoryZoneFinder::find(const Name& name, const RRType& type,
    1430                 :            :                          const FindOptions options)
    1431                 :            : {
    1432                 :            :     return (ZoneFinderContextPtr(
    1433                 :            :                 new Context(*this, options, impl_->find(name, type, NULL,
    1434 [ +  - ][ +  - ]:        562 :                                                         options))));
                 [ +  - ]
    1435                 :            : }
    1436                 :            : 
    1437                 :            : ZoneFinderContextPtr
    1438                 :         23 : InMemoryZoneFinder::findAll(const Name& name,
    1439                 :            :                             std::vector<ConstRRsetPtr>& target,
    1440                 :            :                             const FindOptions options)
    1441                 :            : {
    1442                 :            :     return (ZoneFinderContextPtr(
    1443                 :            :                 new Context(*this, options, impl_->find(name, RRType::ANY(),
    1444 [ +  - ][ +  - ]:         45 :                                                         &target, options))));
                 [ +  - ]
    1445                 :            : }
    1446                 :            : 
    1447                 :            : ZoneFinder::FindNSEC3Result
    1448                 :         22 : InMemoryZoneFinder::findNSEC3(const Name& name, bool recursive) {
    1449 [ +  - ][ +  - ]:         66 :     LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_FINDNSEC3).arg(name).
    1450 [ +  + ][ +  - ]:         44 :         arg(recursive ? "recursive" : "non-recursive");
    1451                 :            : 
    1452         [ +  + ]:         22 :     if (!impl_->zone_data_->nsec3_data_) {
    1453 [ +  - ][ +  - ]:          2 :         isc_throw(DataSourceError,
         [ +  - ][ +  - ]
    1454                 :            :                   "findNSEC3 attempt for non NSEC3 signed zone: " <<
    1455                 :            :                   impl_->origin_ << "/" << impl_->zone_class_);
    1456                 :            :     }
    1457                 :         21 :     const NSEC3Map& map = impl_->zone_data_->nsec3_data_->map_;
    1458         [ +  + ]:         21 :     if (map.empty()) {
    1459 [ +  - ][ +  - ]:          2 :         isc_throw(DataSourceError,
         [ +  - ][ +  - ]
    1460                 :            :                   "findNSEC3 attempt but zone has no NSEC3 RR: " <<
    1461                 :            :                   impl_->origin_ << "/" << impl_->zone_class_);
    1462                 :            :     }
    1463                 :         20 :     const NameComparisonResult cmp_result = name.compare(impl_->origin_);
    1464 [ +  + ][ +  + ]:         20 :     if (cmp_result.getRelation() != NameComparisonResult::EQUAL &&
                 [ +  + ]
    1465                 :            :         cmp_result.getRelation() != NameComparisonResult::SUBDOMAIN) {
    1466 [ +  - ][ +  - ]:          4 :         isc_throw(OutOfZone, "findNSEC3 attempt for out-of-zone name: "
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
    1467                 :            :                   << name << ", zone: " << impl_->origin_ << "/"
    1468                 :            :                   << impl_->zone_class_);
    1469                 :            :     }
    1470                 :            : 
    1471                 :            :     // Convenient shortcuts
    1472                 :         18 :     const NSEC3Hash& nsec3hash = *impl_->zone_data_->nsec3_data_->hash_;
    1473                 :         36 :     const unsigned int olabels = impl_->origin_.getLabelCount();
    1474                 :         18 :     const unsigned int qlabels = name.getLabelCount();
    1475                 :            : 
    1476                 :            :     ConstRBNodeRRsetPtr covering_proof; // placeholder of the next closer proof
    1477                 :            :     // Examine all names from the query name to the origin name, stripping
    1478                 :            :     // the deepest label one by one, until we find a name that has a matching
    1479                 :            :     // NSEC3 hash.
    1480         [ +  + ]:         26 :     for (unsigned int labels = qlabels; labels >= olabels; --labels) {
    1481                 :            :         const string hlabel = nsec3hash.calculate(
    1482 [ +  + ][ +  - ]:         50 :             labels == qlabels ? name : name.split(qlabels - labels, labels));
         [ +  - ][ +  - ]
    1483                 :         25 :         NSEC3Map::const_iterator found = map.lower_bound(hlabel);
    1484 [ +  - ][ +  - ]:         50 :         LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_FINDNSEC3_TRYHASH).
                 [ +  - ]
    1485 [ +  - ][ +  - ]:         25 :             arg(name).arg(labels).arg(hlabel);
         [ +  - ][ +  - ]
    1486                 :            : 
    1487                 :            :         // If the given hash is larger than the largest stored hash or
    1488                 :            :         // the first label doesn't match the target, identify the "previous"
    1489                 :            :         // hash value and remember it as the candidate next closer proof.
    1490 [ +  + ][ +  + ]:         48 :         if (found == map.end() || found->first != hlabel) {
                 [ +  + ]
    1491                 :            :             // If the given hash is larger or smaller than everything,
    1492                 :            :             // the covering proof is the NSEC3 that has the largest hash.
    1493                 :            :             // Note that we know the map isn't empty, so rbegin() is
    1494                 :            :             // safe.
    1495 [ +  + ][ +  + ]:         14 :             if (found == map.end() || found == map.begin()) {
                 [ +  + ]
    1496         [ +  - ]:          6 :                 covering_proof = map.rbegin()->second;
    1497                 :            :             } else {
    1498                 :            :                 // Otherwise, H(found_entry-1) < given_hash < H(found_entry).
    1499                 :            :                 // The covering proof is the first one (and it's valid
    1500                 :            :                 // because found is neither begin nor end)
    1501         [ +  - ]:          8 :                 covering_proof = (--found)->second;
    1502                 :            :             }
    1503         [ +  + ]:         14 :             if (!recursive) {   // in non recursive mode, we are done.
    1504 [ +  - ][ +  - ]:         12 :                 LOG_DEBUG(logger, DBG_TRACE_BASIC,
                 [ +  - ]
    1505                 :            :                           DATASRC_MEM_FINDNSEC3_COVER).
    1506 [ +  - ][ +  - ]:          6 :                     arg(name).arg(*covering_proof);
                 [ +  - ]
    1507                 :            :                 return (FindNSEC3Result(false, labels, covering_proof,
    1508                 :          6 :                                         ConstRRsetPtr()));
    1509                 :            :             }
    1510                 :            :         } else {                // found an exact match.
    1511 [ +  - ][ +  - ]:         22 :                 LOG_DEBUG(logger, DBG_TRACE_BASIC,
                 [ +  - ]
    1512 [ +  - ][ +  - ]:         11 :                           DATASRC_MEM_FINDNSEC3_MATCH).arg(name).arg(labels).
                 [ +  - ]
    1513         [ +  - ]:         22 :                     arg(*found->second);
    1514                 :            :             return (FindNSEC3Result(true, labels, found->second,
    1515                 :         22 :                                     covering_proof));
    1516                 :            :         }
    1517                 :            :     }
    1518                 :            : 
    1519 [ +  - ][ +  - ]:          2 :     isc_throw(DataSourceError, "recursive findNSEC3 mode didn't stop, likely "
         [ +  - ][ +  - ]
                 [ +  - ]
    1520                 :            :               "a broken NSEC3 zone: " << impl_->origin_ << "/"
    1521                 :            :               << impl_->zone_class_);
    1522                 :            : }
    1523                 :            : 
    1524                 :            : result::Result
    1525                 :        221 : InMemoryZoneFinder::add(const ConstRRsetPtr& rrset) {
    1526                 :        221 :     return (impl_->add(rrset, *impl_->zone_data_, NULL));
    1527                 :            : }
    1528                 :            : 
    1529                 :            : namespace {
    1530                 :            : // This should eventually be more generalized.
    1531                 :            : const Name
    1532                 :        488 : getAdditionalName(RRType rrtype, const rdata::Rdata& rdata) {
    1533         [ +  + ]:        488 :     if (rrtype == RRType::NS()) {
    1534         [ +  - ]:        367 :         const generic::NS& ns = dynamic_cast<const generic::NS&>(rdata);
    1535                 :        367 :         return (ns.getNSName());
    1536                 :            :     } else {
    1537                 :            :         // In our usage the only other possible case is MX.
    1538         [ -  + ]:        121 :         assert(rrtype == RRType::MX());
    1539         [ +  - ]:        609 :         const generic::MX& mx = dynamic_cast<const generic::MX&>(rdata);
    1540                 :        121 :         return (mx.getMXName());
    1541                 :            :     }
    1542                 :            : }
    1543                 :            : 
    1544                 :            : void
    1545                 :         13 : convertAndInsert(const DomainPair& rrset_item, DomainPtr dst_domain,
    1546                 :            :                  const Name* dstname)
    1547                 :            : {
    1548                 :            :     // We copy RRSIGs, too, if they are attached in case we need it in
    1549                 :            :     // getAdditional().
    1550                 :            :     dst_domain->insert(DomainPair(rrset_item.first,
    1551                 :            :                                   prepareRRset(*dstname, rrset_item.second,
    1552                 :            :                                                true,
    1553                 :         26 :                                                ZoneFinder::FIND_DNSSEC)));
    1554                 :         13 : }
    1555                 :            : 
    1556                 :            : void
    1557                 :        240 : addAdditional(RBNodeRRset* rrset, ZoneData* zone_data,
    1558                 :            :               vector<RBNodeRRset*>* wild_rrsets)
    1559                 :            : {
    1560                 :        240 :     RdataIteratorPtr rdata_iterator = rrset->getRdataIterator();
    1561                 :        240 :     bool match_wild = false;    // will be true if wildcard match is found
    1562                 :            :     RBTreeNodeChain<Domain> node_path;  // placeholder for findNode()
    1563 [ +  - ][ +  - ]:        689 :     for (; !rdata_iterator->isLast(); rdata_iterator->next()) {
                 [ +  + ]
    1564                 :            :         // For each domain name that requires additional section processing
    1565                 :            :         // in each RDATA, search the tree for the name and remember it if
    1566                 :            :         // found.  If the name is under a zone cut (for a delegation to a
    1567                 :            :         // child zone), mark the node as "GLUE", so we can selectively
    1568                 :            :         // include/exclude them when we use it.
    1569                 :            : 
    1570         [ +  - ]:        449 :         const Name& name = getAdditionalName(rrset->getType(),
    1571 [ +  - ][ +  - ]:       1347 :                                              rdata_iterator->getCurrent());
    1572                 :            :         // if the name is not in or below this zone, skip it
    1573                 :            :         const NameComparisonResult::NameRelation reln =
    1574         [ +  - ]:        449 :             name.compare(zone_data->origin_data_->getName()).getRelation();
    1575         [ +  + ]:        449 :         if (reln != NameComparisonResult::SUBDOMAIN &&
    1576                 :            :             reln != NameComparisonResult::EQUAL) {
    1577                 :         13 :             continue;
    1578                 :            :         }
    1579                 :            :         node_path.clear();
    1580                 :            :         const ZoneData::FindMutableNodeResult result =
    1581                 :            :             zone_data->findNode<ZoneData::FindMutableNodeResult>(
    1582         [ +  - ]:        436 :                 name, node_path, ZoneFinder::FIND_GLUE_OK);
    1583         [ +  + ]:        436 :         if (result.code != ZoneFinder::SUCCESS) {
    1584                 :            :             // We are not interested in anything but a successful match.
    1585                 :         13 :             continue;
    1586                 :            :         }
    1587                 :        423 :         DomainNode* node = result.node;
    1588         [ -  + ]:        423 :         assert(node != NULL);
    1589         [ +  + ]:        462 :         if ((result.flags & ZoneData::FindNodeResult::FIND_ZONECUT) != 0 ||
           [ +  +  +  + ]
                 [ +  + ]
    1590                 :            :             (node->getFlag(DomainNode::FLAG_CALLBACK) &&
    1591                 :         39 :              node->getData()->find(RRType::NS()) != node->getData()->end())) {
    1592                 :            :             // The node is under or at a zone cut; mark it as a glue.
    1593         [ +  - ]:        134 :             node->setFlag(domain_flag::GLUE);
    1594                 :            :         }
    1595                 :            : 
    1596                 :            :         // A rare case: the additional name may have to be expanded with a
    1597                 :            :         // wildcard.  We'll store the name in a separate auxiliary tree,
    1598                 :            :         // copying all RRsets of the original wildcard node with expanding
    1599                 :            :         // the owner name.  This is costly in terms of memory, but this case
    1600                 :            :         // should be pretty rare.  On the other hand we won't have to worry
    1601                 :            :         // about wildcard expansion in getAdditional, which is quite
    1602                 :            :         // performance sensitive.
    1603                 :        423 :         DomainNode* wildnode = NULL;
    1604         [ +  + ]:        423 :         if ((result.flags & ZoneData::FindNodeResult::FIND_WILDCARD) != 0) {
    1605                 :            :             // Wildcard and glue shouldn't coexist.  Make it sure here.
    1606         [ -  + ]:         26 :             assert(!node->getFlag(domain_flag::GLUE));
    1607                 :            : 
    1608 [ +  - ][ +  - ]:         26 :             if (zone_data->getAuxWildDomains().insert(name, &wildnode)
                 [ +  - ]
    1609                 :            :                 == DomainTree::SUCCESS) {
    1610                 :            :                 // If we first insert the node, copy the RRsets.  If the
    1611                 :            :                 // original node was empty, we add empty data so
    1612                 :            :                 // addWildAdditional() can get an exactmatch for this name.
    1613 [ +  - ][ +  - ]:         26 :                 DomainPtr dst_domain(new Domain);
    1614         [ +  + ]:         26 :                 if (!node->isEmpty()) {
    1615                 :         13 :                     for_each(node->getData()->begin(), node->getData()->end(),
    1616                 :            :                              boost::bind(convertAndInsert, _1, dst_domain,
    1617   [ +  -  +  - ]:         26 :                                          &name));
    1618                 :            :                 }
    1619                 :         26 :                 wildnode->setData(dst_domain);
    1620                 :            :                 // Mark the node as "wildcard expanded" so it can be
    1621                 :            :                 // distinguished at lookup time.
    1622         [ +  - ]:         26 :                 wildnode->setFlag(domain_flag::WILD_EXPANDED);
    1623                 :            :             }
    1624                 :         26 :             match_wild = true;
    1625                 :         26 :             node = wildnode;
    1626                 :            :         }
    1627                 :            : 
    1628                 :            :         // If this name wasn't subject to wildcard substitution, we can add
    1629                 :            :         // the additional information to the RRset now; otherwise I'll defer
    1630                 :            :         // it until the entire auxiliary tree is built (pointers may be
    1631                 :            :         // invalidated as we build it).
    1632         [ +  + ]:        423 :         if (wildnode == NULL) {
    1633                 :            :             // Note that node may be empty.  We should keep it in the list
    1634                 :            :             // in case we dynamically update the tree and it becomes non empty
    1635                 :            :             // (which is not supported yet)
    1636         [ +  - ]:        397 :             rrset->addAdditionalNode(AdditionalNodeInfo(node));
    1637                 :            :         }
    1638                 :            :     }
    1639                 :            : 
    1640         [ +  + ]:        240 :     if (match_wild) {
    1641         [ +  - ]:         13 :         wild_rrsets->push_back(rrset);
    1642                 :            :     }
    1643                 :        240 : }
    1644                 :            : 
    1645                 :            : void
    1646                 :         13 : addWildAdditional(RBNodeRRset* rrset, ZoneData* zone_data) {
    1647                 :            :     // Similar to addAdditional(), but due to the first stage we know that
    1648                 :            :     // the rrset should contain a name stored in the auxiliary trees, and
    1649                 :            :     // that it should be found as an exact match.  The RRset may have other
    1650                 :            :     // names that didn't require wildcard expansion, but we can simply ignore
    1651                 :            :     // them in this context.  (Note that if we find an exact match in the
    1652                 :            :     // auxiliary tree, it shouldn't be in the original zone; otherwise it
    1653                 :            :     // shouldn't have resulted in wildcard in the first place).
    1654                 :            : 
    1655                 :         13 :     RdataIteratorPtr rdata_iterator = rrset->getRdataIterator();
    1656 [ +  - ][ +  - ]:         52 :     for (; !rdata_iterator->isLast(); rdata_iterator->next()) {
                 [ +  + ]
    1657         [ +  - ]:         39 :         const Name& name = getAdditionalName(rrset->getType(),
    1658 [ +  - ][ +  - ]:        117 :                                              rdata_iterator->getCurrent());
    1659                 :         39 :         DomainNode* wildnode = NULL;
    1660 [ +  - ][ +  - ]:         39 :         if (zone_data->getAuxWildDomains().find(name, &wildnode) ==
                 [ +  + ]
    1661                 :            :             DomainTree::EXACTMATCH) {
    1662         [ +  - ]:         26 :             rrset->addAdditionalNode(AdditionalNodeInfo(wildnode));
    1663                 :            :         }
    1664                 :            :     }
    1665                 :         13 : }
    1666                 :            : }
    1667                 :            : 
    1668                 :            : void
    1669                 :         63 : InMemoryZoneFinder::InMemoryZoneFinderImpl::load(
    1670                 :            :     const string& filename,
    1671                 :            :     boost::function<void(LoadCallback)> rrset_installer)
    1672                 :            : {
    1673                 :         63 :     vector<RBNodeRRset*> need_additionals;
    1674         [ +  - ]:        126 :     scoped_ptr<ZoneData> tmp(new ZoneData(origin_));
           [ +  -  +  - ]
    1675                 :            : 
    1676                 :            :     rrset_installer(boost::bind(&InMemoryZoneFinderImpl::addFromLoad, this,
    1677         [ +  - ]:        126 :                                 _1, tmp.get(), &need_additionals));
    1678                 :            : 
    1679                 :         55 :     vector<RBNodeRRset*> wild_additionals;
    1680                 :            :     for_each(need_additionals.begin(), need_additionals.end(),
    1681                 :         55 :              boost::bind(addAdditional, _1, tmp.get(), &wild_additionals));
    1682                 :            :     for_each(wild_additionals.begin(), wild_additionals.end(),
    1683                 :         55 :              boost::bind(addWildAdditional, _1, tmp.get()));
    1684                 :            : 
    1685                 :            :     // If the zone is NSEC3-signed, check if it has NSEC3PARAM
    1686         [ +  + ]:        110 :     if (tmp->nsec3_data_) {
    1687                 :            :         // Note: origin_data_ is set on creation of ZoneData, and the load
    1688                 :            :         // process only adds new nodes (and their data), so this assertion
    1689                 :            :         // should hold.
    1690 [ +  - ][ -  + ]:         16 :         assert(tmp->origin_data_ != NULL && !tmp->origin_data_->isEmpty());
    1691         [ +  + ]:         32 :         if (tmp->origin_data_->getData()->find(RRType::NSEC3PARAM()) ==
    1692                 :         32 :             tmp->origin_data_->getData()->end()) {
    1693 [ +  - ][ +  - ]:          2 :             LOG_WARN(logger, DATASRC_MEM_NO_NSEC3PARAM).
                 [ +  - ]
    1694 [ +  - ][ +  - ]:          1 :                 arg(origin_).arg(zone_class_);
                 [ +  - ]
    1695                 :            :         }
    1696                 :            :     }
    1697                 :            : 
    1698                 :            :     // If it went well, put it inside
    1699                 :         55 :     file_name_ = filename;
    1700                 :         55 :     tmp.swap(zone_data_);
    1701                 :            :     // And let the old data die with tmp
    1702                 :         55 : }
    1703                 :            : 
    1704                 :            : namespace {
    1705                 :            : // A wrapper for dns::masterLoad used by load() below.  Essentially it
    1706                 :            : // converts the two callback types.  Note the mostly redundant wrapper of
    1707                 :            : // boost::bind.  It converts function<void(ConstRRsetPtr)> to
    1708                 :            : // function<void(RRsetPtr)> (masterLoad() expects the latter).  SunStudio
    1709                 :            : // doesn't seem to do this conversion if we just pass 'callback'.
    1710                 :            : void
    1711                 :         58 : masterLoadWrapper(const char* const filename, const Name& origin,
    1712                 :            :                   const RRClass& zone_class, LoadCallback callback)
    1713                 :            : {
    1714         [ +  + ]:        174 :     masterLoad(filename, origin, zone_class, boost::bind(callback, _1));
    1715                 :         51 : }
    1716                 :            : 
    1717                 :            : // The installer called from Impl::load() for the iterator version of load().
    1718                 :            : void
    1719                 :          5 : generateRRsetFromIterator(ZoneIterator* iterator, LoadCallback callback) {
    1720                 :            :     ConstRRsetPtr rrset;
    1721         [ +  - ]:          5 :     vector<ConstRRsetPtr> rrsigs; // placeholder for RRSIGs until "commitable".
    1722                 :            : 
    1723                 :            :     // The current internal implementation assumes an RRSIG is always added
    1724                 :            :     // after the RRset they cover.  So we store any RRSIGs in 'rrsigs' until
    1725                 :            :     // it's safe to add them; based on our assumption if the owner name
    1726                 :            :     // changes, all covered RRsets of the previous name should have been
    1727                 :            :     // installed and any pending RRSIGs can be added at that point.  RRSIGs
    1728                 :            :     // of the last name from the iterator must be added separately.
    1729 [ +  - ][ +  - ]:         96 :     while ((rrset = iterator->getNextRRset()) != NULL) {
                 [ +  + ]
    1730 [ +  + ][ +  - ]:         50 :         if (!rrsigs.empty() && rrset->getName() != rrsigs[0]->getName()) {
         [ +  - ][ +  + ]
                 [ +  + ]
    1731 [ +  + ][ +  - ]:         19 :             BOOST_FOREACH(ConstRRsetPtr sig_rrset, rrsigs) {
         [ +  - ][ +  + ]
                 [ +  + ]
    1732         [ +  - ]:          4 :                 callback(sig_rrset);
    1733                 :            :             }
    1734                 :            :             rrsigs.clear();
    1735                 :            :         }
    1736 [ +  - ][ +  + ]:         44 :         if (rrset->getType() == RRType::RRSIG()) {
    1737         [ +  - ]:          5 :             rrsigs.push_back(rrset);
    1738                 :            :         } else {
    1739         [ +  + ]:         39 :             callback(rrset);
    1740                 :            :         }
    1741                 :            :     }
    1742                 :            : 
    1743 [ +  + ][ +  - ]:          8 :     BOOST_FOREACH(ConstRRsetPtr sig_rrset, rrsigs) {
         [ +  - ][ +  + ]
                 [ +  + ]
    1744         [ +  - ]:          1 :         callback(sig_rrset);
    1745                 :            :     }
    1746                 :          4 : }
    1747                 :            : }
    1748                 :            : 
    1749                 :            : void
    1750                 :         58 : InMemoryZoneFinder::load(const string& filename) {
    1751 [ +  - ][ +  - ]:        116 :     LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_LOAD).arg(getOrigin()).
         [ +  - ][ +  - ]
    1752         [ +  - ]:         58 :         arg(filename);
    1753                 :            : 
    1754                 :            :     impl_->load(filename,
    1755                 :         58 :                 boost::bind(masterLoadWrapper, filename.c_str(), getOrigin(),
    1756   [ +  -  +  + ]:        116 :                             getClass(), _1));
                 [ +  - ]
    1757                 :         51 : }
    1758                 :            : 
    1759                 :            : void
    1760                 :          5 : InMemoryZoneFinder::load(ZoneIterator& iterator) {
    1761                 :          5 :     impl_->load(string(),
    1762         [ +  + ]:         10 :                 boost::bind(generateRRsetFromIterator, &iterator, _1));
    1763                 :          4 : }
    1764                 :            : 
    1765                 :            : void
    1766                 :          4 : InMemoryZoneFinder::swap(InMemoryZoneFinder& zone_finder) {
    1767   [ +  -  +  - ]:         12 :     LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_SWAP).arg(getOrigin()).
         [ +  - ][ +  - ]
                 [ +  - ]
    1768         [ +  - ]:         12 :         arg(zone_finder.getOrigin());
    1769                 :          4 :     std::swap(impl_, zone_finder.impl_);
    1770                 :          4 : }
    1771                 :            : 
    1772                 :            : const string
    1773                 :         10 : InMemoryZoneFinder::getFileName() const {
    1774                 :         10 :     return (impl_->file_name_);
    1775                 :            : }
    1776                 :            : 
    1777                 :            : isc::dns::Name
    1778                 :          1 : InMemoryZoneFinder::findPreviousName(const isc::dns::Name&) const {
    1779 [ +  - ][ +  - ]:          2 :     isc_throw(NotImplemented, "InMemory data source doesn't support DNSSEC "
    1780                 :            :               "yet, can't find previous name");
    1781                 :            : }
    1782                 :            : 
    1783                 :            : /// Implementation details for \c InMemoryClient hidden from the public
    1784                 :            : /// interface.
    1785                 :            : ///
    1786                 :            : /// For now, \c InMemoryClient only contains a \c ZoneTable object, which
    1787                 :            : /// consists of (pointers to) \c InMemoryZoneFinder objects, we may add more
    1788                 :            : /// member variables later for new features.
    1789         [ +  - ]:        158 : class InMemoryClient::InMemoryClientImpl {
    1790                 :            : public:
    1791         [ +  - ]:        158 :     InMemoryClientImpl() : zone_count(0) {}
    1792                 :            :     unsigned int zone_count;
    1793                 :            :     ZoneTable zone_table;
    1794                 :            : };
    1795                 :            : 
    1796         [ +  - ]:        158 : InMemoryClient::InMemoryClient() : impl_(new InMemoryClientImpl)
    1797                 :        158 : {}
    1798                 :            : 
    1799                 :        213 : InMemoryClient::~InMemoryClient() {
    1800         [ +  - ]:        316 :     delete impl_;
    1801                 :        213 : }
    1802                 :            : 
    1803                 :            : unsigned int
    1804                 :         19 : InMemoryClient::getZoneCount() const {
    1805                 :         19 :     return (impl_->zone_count);
    1806                 :            : }
    1807                 :            : 
    1808                 :            : result::Result
    1809                 :        161 : InMemoryClient::addZone(ZoneFinderPtr zone_finder) {
    1810         [ +  + ]:        161 :     if (!zone_finder) {
    1811         [ +  - ]:          2 :         isc_throw(InvalidParameter,
    1812                 :            :                   "Null pointer is passed to InMemoryClient::addZone()");
    1813                 :            :     }
    1814                 :            : 
    1815 [ +  - ][ +  - ]:        320 :     LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_ADD_ZONE).
    1816 [ +  - ][ +  - ]:        480 :         arg(zone_finder->getOrigin()).arg(zone_finder->getClass().toText());
         [ +  - ][ +  - ]
    1817                 :            : 
    1818         [ +  - ]:        160 :     const result::Result result = impl_->zone_table.addZone(zone_finder);
    1819         [ +  + ]:        160 :     if (result == result::SUCCESS) {
    1820                 :        156 :         ++impl_->zone_count;
    1821                 :            :     }
    1822                 :        160 :     return (result);
    1823                 :            : }
    1824                 :            : 
    1825                 :            : InMemoryClient::FindResult
    1826                 :        176 : InMemoryClient::findZone(const isc::dns::Name& name) const {
    1827 [ +  - ][ +  - ]:        176 :     LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_FIND_ZONE).arg(name);
    1828                 :        176 :     ZoneTable::FindResult result(impl_->zone_table.findZone(name));
    1829                 :        176 :     return (FindResult(result.code, result.zone));
    1830                 :            : }
    1831                 :            : 
    1832                 :            : namespace {
    1833                 :            : 
    1834                 :          8 : class MemoryIterator : public ZoneIterator {
    1835                 :            : private:
    1836                 :            :     RBTreeNodeChain<Domain> chain_;
    1837                 :            :     Domain::const_iterator dom_iterator_;
    1838                 :            :     const DomainTree& tree_;
    1839                 :            :     const DomainNode* node_;
    1840                 :            :     // Only used when separate_rrs_ is true
    1841                 :            :     RdataIteratorPtr rdata_iterator_;
    1842                 :            :     bool separate_rrs_;
    1843                 :            :     bool ready_;
    1844                 :            : public:
    1845                 :            :     MemoryIterator(const DomainTree& tree, const Name& origin, bool separate_rrs) :
    1846                 :            :         tree_(tree),
    1847                 :            :         separate_rrs_(separate_rrs),
    1848                 :         20 :         ready_(true)
    1849                 :            :     {
    1850                 :            :         // Find the first node (origin) and preserve the node chain for future
    1851                 :            :         // searches
    1852                 :          8 :         DomainTree::Result result(tree_.find(origin, &node_, chain_));
    1853                 :            :         // It can't happen that the origin is not in there
    1854         [ -  + ]:          4 :         if (result != DomainTree::EXACTMATCH) {
    1855 [ #  # ][ #  # ]:          0 :             isc_throw(Unexpected,
    1856                 :            :                       "In-memory zone corrupted, missing origin node");
    1857                 :            :         }
    1858                 :            :         // Initialize the iterator if there's somewhere to point to
    1859 [ +  - ][ -  + ]:          8 :         if (node_ != NULL && node_->getData() != DomainPtr()) {
         [ +  - ][ +  - ]
    1860                 :          4 :             dom_iterator_ = node_->getData()->begin();
    1861 [ +  + ][ +  + ]:          4 :             if (separate_rrs_ && dom_iterator_ != node_->getData()->end()) {
                 [ +  + ]
    1862 [ +  - ][ +  - ]:          1 :                 rdata_iterator_ = dom_iterator_->second->getRdataIterator();
    1863                 :            :             }
    1864                 :            :         }
    1865                 :            :     }
    1866                 :            : 
    1867                 :         13 :     virtual ConstRRsetPtr getNextRRset() {
    1868         [ +  + ]:         13 :         if (!ready_) {
    1869         [ +  - ]:          4 :             isc_throw(Unexpected, "Iterating past the zone end");
    1870                 :            :         }
    1871                 :            :         /*
    1872                 :            :          * This cycle finds the first nonempty node with yet unused RRset.
    1873                 :            :          * If it is NULL, we run out of nodes. If it is empty, it doesn't
    1874                 :            :          * contain any RRsets. If we are at the end, just get to next one.
    1875                 :            :          */
    1876         [ +  + ]:         43 :         while (node_ != NULL && (node_->getData() == DomainPtr() ||
           [ +  -  +  + ]
         [ +  + ][ +  + ]
    1877                 :         13 :                                  dom_iterator_ == node_->getData()->end())) {
    1878                 :          6 :             node_ = tree_.nextNode(chain_);
    1879                 :            :             // If there's a node, initialize the iterator and check next time
    1880                 :            :             // if the map is empty or not
    1881 [ +  + ][ -  + ]:          8 :             if (node_ != NULL && node_->getData() != NULL) {
                 [ +  + ]
    1882                 :          2 :                 dom_iterator_ = node_->getData()->begin();
    1883                 :            :                 // New RRset, so get a new rdata iterator
    1884         [ +  + ]:          2 :                 if (separate_rrs_) {
    1885         [ +  - ]:          1 :                     rdata_iterator_ = dom_iterator_->second->getRdataIterator();
    1886                 :            :                 }
    1887                 :            :             }
    1888                 :            :         }
    1889         [ +  + ]:         11 :         if (node_ == NULL) {
    1890                 :            :             // That's all, folks
    1891                 :          4 :             ready_ = false;
    1892                 :            :             return (ConstRRsetPtr());
    1893                 :            :         }
    1894                 :            : 
    1895         [ +  + ]:          7 :         if (separate_rrs_) {
    1896                 :            :             // For separate rrs, reconstruct a new RRset with just the
    1897                 :            :             // 'current' rdata
    1898                 :          4 :             RRsetPtr result(new RRset(dom_iterator_->second->getName(),
    1899                 :          4 :                                       dom_iterator_->second->getClass(),
    1900                 :          4 :                                       dom_iterator_->second->getType(),
    1901         [ +  - ]:         12 :                                       dom_iterator_->second->getTTL()));
    1902 [ +  - ][ +  - ]:          4 :             result->addRdata(rdata_iterator_->getCurrent());
    1903         [ +  - ]:          4 :             rdata_iterator_->next();
    1904 [ +  - ][ +  + ]:          4 :             if (rdata_iterator_->isLast()) {
    1905                 :            :                 // all used up, next.
    1906                 :          3 :                 ++dom_iterator_;
    1907                 :            :                 // New RRset, so get a new rdata iterator, but only if this
    1908                 :            :                 // was not the final RRset in the chain
    1909         [ +  + ]:          3 :                 if (dom_iterator_ != node_->getData()->end()) {
    1910 [ +  - ][ +  - ]:          1 :                     rdata_iterator_ = dom_iterator_->second->getRdataIterator();
    1911                 :            :                 }
    1912                 :            :             }
    1913                 :            :             return (result);
    1914                 :            :         } else {
    1915                 :            :             // The iterator points to the next yet unused RRset now
    1916                 :          6 :             ConstRRsetPtr result(dom_iterator_->second);
    1917                 :            : 
    1918                 :            :             // This one is used, move it to the next time for next call
    1919                 :          3 :             ++dom_iterator_;
    1920                 :            : 
    1921                 :            :             return (result);
    1922                 :            :         }
    1923                 :            :     }
    1924                 :            : 
    1925                 :          0 :     virtual ConstRRsetPtr getSOA() const {
    1926 [ #  # ][ #  # ]:          0 :         isc_throw(NotImplemented, "Not imelemented");
    1927                 :            :     }
    1928                 :            : };
    1929                 :            : 
    1930                 :            : } // End of anonymous namespace
    1931                 :            : 
    1932                 :            : ZoneIteratorPtr
    1933                 :          9 : InMemoryClient::getIterator(const Name& name, bool separate_rrs) const {
    1934                 :          9 :     ZoneTable::FindResult result(impl_->zone_table.findZone(name));
    1935         [ +  + ]:          9 :     if (result.code != result::SUCCESS) {
    1936 [ +  - ][ +  - ]:         10 :         isc_throw(DataSourceError, "No such zone: " + name.toText());
         [ +  - ][ +  - ]
    1937                 :            :     }
    1938                 :            : 
    1939                 :            :     const InMemoryZoneFinder*
    1940         [ +  - ]:          4 :         zone(dynamic_cast<const InMemoryZoneFinder*>(result.zone.get()));
    1941         [ -  + ]:          4 :     if (zone == NULL) {
    1942                 :            :         /*
    1943                 :            :          * TODO: This can happen only during some of the tests and only as
    1944                 :            :          * a temporary solution. This should be fixed by #1159 and then
    1945                 :            :          * this cast and check shouldn't be necessary. We don't have
    1946                 :            :          * test for handling a "can not happen" condition.
    1947                 :            :          */
    1948 [ #  # ][ #  # ]:          0 :         isc_throw(Unexpected, "The zone at " + name.toText() +
         [ #  # ][ #  # ]
    1949                 :            :                   " is not InMemoryZoneFinder");
    1950                 :            :     }
    1951                 :            :     return (ZoneIteratorPtr(new MemoryIterator(
    1952                 :          4 :                                 zone->impl_->zone_data_->domains_, name,
    1953         [ +  - ]:          8 :                                 separate_rrs)));
    1954                 :            : }
    1955                 :            : 
    1956                 :            : ZoneUpdaterPtr
    1957                 :          2 : InMemoryClient::getUpdater(const isc::dns::Name&, bool, bool) const {
    1958 [ +  - ][ +  - ]:          4 :     isc_throw(isc::NotImplemented, "Update attempt on in memory data source");
    1959                 :            : }
    1960                 :            : 
    1961                 :            : pair<ZoneJournalReader::Result, ZoneJournalReaderPtr>
    1962                 :          0 : InMemoryClient::getJournalReader(const isc::dns::Name&, uint32_t,
    1963                 :            :                                  uint32_t) const
    1964                 :            : {
    1965 [ #  # ][ #  # ]:          0 :     isc_throw(isc::NotImplemented, "Journaling isn't supported for "
    1966                 :            :               "in memory data source");
    1967                 :            : }
    1968                 :            : 
    1969                 :            : } // end of namespace datasrc
    1970                 :       1391 : } // end of namespace isc

Generated by: LCOV version 1.9