BIND 10 master, updated. 0de32e7fe21e18069d26e3d282ac8078c852f004 Merge branch 'master' into trac2432

BIND 10 source code commits bind10-changes at lists.isc.org
Mon Jan 7 15:16:48 UTC 2013


The branch, master has been updated
       via  0de32e7fe21e18069d26e3d282ac8078c852f004 (commit)
       via  806865cd2e830785f0d377d759e7475b9e1f640b (commit)
       via  e7f9ab53656fdfb8a1b27c7056f8dc2c86d8f966 (commit)
       via  35d02013f29d19fabf678089ba97db2e67ab3f25 (commit)
       via  004823862f69853d3c4acd6f8e0bc60925c25ed1 (commit)
       via  1fa69473d881a5c31cd802563f2c398e1f6d1ecb (commit)
       via  3baea8cf898f2e9dcd35c88e48999b8112732f9d (commit)
       via  08c2f82000bacb76d0602cc9c428637aed0baf21 (commit)
       via  dd444334eb873bd925639e3141c3a863fad1e47a (commit)
       via  5d3af5f896df69f42590921a44650745411673fa (commit)
       via  bbb8a8f0ed42862b7e5b54e7611cb0d0e364203b (commit)
       via  ee424bbc727b754b8030fb2adaa69c578f096de9 (commit)
       via  bdf19add5fca40dbc91c6ce4c0d87d8bb6080bde (commit)
       via  cfbb9eada0a6e0ff8a2faead73f870d3ca3400fc (commit)
       via  8bca74f57a81fa7e2dc2569692b253dbf19270b4 (commit)
       via  34929974f3655f19029d83234e4c5b89b85eaf99 (commit)
       via  98d515d5e653a75762b5da424555ac301e7f9af5 (commit)
       via  4a15ebc6f38bf2b2fe66a069a58f22f89e8ec6fc (commit)
       via  8f149bd04986ba2542e86c7ce77e5d0e92df16ea (commit)
       via  201672389bfa78c8eb59e122f6f117d1eb0644ed (commit)
       via  fc882313210b117eeec371b33796a54a4094c1d3 (commit)
       via  82d0b7f2ab2fcca6daafdcd5aae06cc0efcd2ffd (commit)
       via  2205f81d523ba1175614c6a7ee54904b74ea1a43 (commit)
       via  a9c8b8f3cd7ae57265efd4e01c51cbb4526c038f (commit)
       via  12b24545cb9aeb86229694cda68c71577587f125 (commit)
       via  0a14dac0417402193dbcd50cb73360aeef9aabb2 (commit)
       via  9cb41a2f06b35290e72eccc8246d8abf57f6e929 (commit)
       via  7383457001cd2b6d78ec755f1cf20fa4529a43ab (commit)
       via  e6c05e218034a214844e1d4ab8b8c1060ec05489 (commit)
       via  b5735838a44da418d7d66724c8bb53c2d4d1b3c7 (commit)
       via  e4a823ad343ed077f88da1e581d0486c9b634a35 (commit)
       via  6c738ab17c6b6632f1a607cea6cea480fd1c72aa (commit)
       via  7eee12217563565248904b7051a6d68f2374ebe0 (commit)
       via  b5aa1d1b12636ba96e3fff48e27fb6acf6e38333 (commit)
       via  2fc0ce200dfa85a5f7baa577750b3c3fe8032f7d (commit)
       via  d33dd125553aa9702e1a29a6c0e30da9ffffe53b (commit)
       via  c645605f43d14ed37a22369c3f5ac177acdeb7cd (commit)
      from  83e71312ca3631e5a8f2364bb8434d69ae000ee1 (commit)

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

- Log -----------------------------------------------------------------
commit 0de32e7fe21e18069d26e3d282ac8078c852f004
Merge: 806865c 83e7131
Author: Mukund Sivaraman <muks at isc.org>
Date:   Mon Jan 7 20:02:44 2013 +0530

    Merge branch 'master' into trac2432

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

Summary of changes:
 src/bin/resolver/resolver.h                    |    6 +-
 src/lib/cc/data.h                              |    3 +-
 src/lib/config/config_data.h                   |    4 +-
 src/lib/dns/Makefile.am                        |    4 +
 src/lib/dns/rrset_collection.cc                |  128 ++++++++++++
 src/lib/dns/rrset_collection.h                 |  172 +++++++++++++++++
 src/lib/dns/rrset_collection_base.h            |  163 ++++++++++++++++
 src/lib/dns/tests/Makefile.am                  |    1 +
 src/lib/dns/tests/rrset_collection_unittest.cc |  246 ++++++++++++++++++++++++
 9 files changed, 720 insertions(+), 7 deletions(-)
 create mode 100644 src/lib/dns/rrset_collection.cc
 create mode 100644 src/lib/dns/rrset_collection.h
 create mode 100644 src/lib/dns/rrset_collection_base.h
 create mode 100644 src/lib/dns/tests/rrset_collection_unittest.cc

-----------------------------------------------------------------------
diff --git a/src/bin/resolver/resolver.h b/src/bin/resolver/resolver.h
index cc0f09f..725aa85 100644
--- a/src/bin/resolver/resolver.h
+++ b/src/bin/resolver/resolver.h
@@ -200,14 +200,14 @@ public:
     /**
      * \short Get info about timeouts.
      *
-     * \returns Timeout and retries (as described in setTimeouts).
+     * \return Timeout and retries (as described in setTimeouts).
      */
     std::pair<int, unsigned> getTimeouts() const;
 
     /**
      * \brief Get the timeout for outgoing queries
      *
-     * \returns Timeout for outgoing queries
+     * \return Timeout for outgoing queries
      */
     int getQueryTimeout() const;
 
@@ -218,7 +218,7 @@ public:
      * (internal resolving on the query will continue, see
      * \c getLookupTimeout())
      * 
-     * \returns Timeout for outgoing queries
+     * \return Timeout for outgoing queries
      */
     int getClientTimeout() const;
 
diff --git a/src/lib/cc/data.h b/src/lib/cc/data.h
index bb84ae2..db25d9f 100644
--- a/src/lib/cc/data.h
+++ b/src/lib/cc/data.h
@@ -109,8 +109,7 @@ public:
 
     /// \name pure virtuals, every derived class must implement these
 
-    /// \returns true if the other ElementPtr has the same type and
-    ///          value
+    /// \return true if the other ElementPtr has the same type and value
     virtual bool equals(const Element& other) const = 0;
 
     /// Converts the Element to JSON format and appends it to
diff --git a/src/lib/config/config_data.h b/src/lib/config/config_data.h
index 0bb1bfd..1be7c7a 100644
--- a/src/lib/config/config_data.h
+++ b/src/lib/config/config_data.h
@@ -93,8 +93,8 @@ public:
     void setLocalConfig(isc::data::ElementPtr config) { _config = config; }
 
     /// Returns the local (i.e. non-default) configuration.
-    /// \returns An ElementPtr pointing to a MapElement containing all
-    ///          non-default configuration options.
+    /// \return An ElementPtr pointing to a MapElement containing all
+    ///         non-default configuration options.
     isc::data::ElementPtr getLocalConfig() { return (_config); }
 
     /// Returns a list of all possible configuration options as specified
diff --git a/src/lib/dns/Makefile.am b/src/lib/dns/Makefile.am
index 8525842..6d8d162 100644
--- a/src/lib/dns/Makefile.am
+++ b/src/lib/dns/Makefile.am
@@ -127,6 +127,8 @@ libb10_dns___la_SOURCES += tsigrecord.h tsigrecord.cc
 libb10_dns___la_SOURCES += character_string.h character_string.cc
 libb10_dns___la_SOURCES += master_loader_callbacks.h master_loader_callbacks.cc
 libb10_dns___la_SOURCES += master_loader.h
+libb10_dns___la_SOURCES += rrset_collection_base.h
+libb10_dns___la_SOURCES += rrset_collection.h rrset_collection.cc
 libb10_dns___la_SOURCES += rdata/generic/detail/char_string.h
 libb10_dns___la_SOURCES += rdata/generic/detail/char_string.cc
 libb10_dns___la_SOURCES += rdata/generic/detail/nsec_bitmap.h
@@ -170,6 +172,8 @@ libdns___include_HEADERS = \
 	rdata.h \
 	rrparamregistry.h \
 	rrset.h \
+	rrset_collection_base.h \
+	rrset_collection.h \
 	rrttl.h \
 	tsigkey.h
 # Purposely not installing these headers:
diff --git a/src/lib/dns/rrset_collection.cc b/src/lib/dns/rrset_collection.cc
new file mode 100644
index 0000000..8711c3f
--- /dev/null
+++ b/src/lib/dns/rrset_collection.cc
@@ -0,0 +1,128 @@
+// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <dns/rrset_collection.h>
+#include <dns/master_loader_callbacks.h>
+#include <dns/master_loader.h>
+#include <dns/rrcollator.h>
+
+#include <exceptions/exceptions.h>
+
+#include <boost/bind.hpp>
+
+using namespace isc;
+
+namespace isc {
+namespace dns {
+
+void
+RRsetCollection::loaderCallback(const std::string&, size_t, const std::string&)
+{
+     // We just ignore callbacks for errors and warnings.
+}
+
+void
+RRsetCollection::addRRset(RRsetPtr rrset) {
+    const CollectionKey key(rrset->getClass(), rrset->getType(),
+                            rrset->getName());
+    CollectionMap::const_iterator it = rrsets_.find(key);
+    if (it != rrsets_.end()) {
+        isc_throw(InvalidParameter,
+                  "RRset for " << rrset->getName() << "/" << rrset->getClass()
+                  << " with type " << rrset->getType() << " already exists");
+    }
+
+    rrsets_.insert(std::pair<CollectionKey, RRsetPtr>(key, rrset));
+}
+
+template<typename T>
+void
+RRsetCollection::constructHelper(T source, const isc::dns::Name& origin,
+                                 const isc::dns::RRClass& rrclass)
+{
+    RRCollator collator(boost::bind(&RRsetCollection::addRRset, this, _1));
+    MasterLoaderCallbacks callbacks
+        (boost::bind(&RRsetCollection::loaderCallback, this, _1, _2, _3),
+         boost::bind(&RRsetCollection::loaderCallback, this, _1, _2, _3));
+    MasterLoader loader(source, origin, rrclass, callbacks,
+                        collator.getCallback(),
+                        MasterLoader::DEFAULT);
+    loader.load();
+    collator.flush();
+}
+
+RRsetCollection::RRsetCollection(const char* filename, const Name& origin,
+                                 const RRClass& rrclass)
+{
+    constructHelper(filename, origin, rrclass);
+}
+
+RRsetCollection::RRsetCollection(std::istream& input_stream, const Name& origin,
+                                 const RRClass& rrclass)
+{
+    constructHelper<std::istream&>(input_stream, origin, rrclass);
+}
+
+RRsetPtr
+RRsetCollection::find(const Name& name, const RRClass& rrclass,
+                      const RRType& rrtype) {
+    const CollectionKey key(rrclass, rrtype, name);
+    CollectionMap::iterator it = rrsets_.find(key);
+    if (it != rrsets_.end()) {
+        return (it->second);
+    }
+    return (RRsetPtr());
+}
+
+ConstRRsetPtr
+RRsetCollection::find(const Name& name, const RRClass& rrclass,
+                      const RRType& rrtype) const
+{
+    const CollectionKey key(rrclass, rrtype, name);
+    CollectionMap::const_iterator it = rrsets_.find(key);
+    if (it != rrsets_.end()) {
+        return (it->second);
+    }
+    return (ConstRRsetPtr());
+}
+
+bool
+RRsetCollection::removeRRset(const Name& name, const RRClass& rrclass,
+                             const RRType& rrtype)
+{
+    const CollectionKey key(rrclass, rrtype, name);
+
+    CollectionMap::iterator it = rrsets_.find(key);
+    if (it == rrsets_.end()) {
+        return (false);
+    }
+
+    rrsets_.erase(it);
+    return (true);
+}
+
+RRsetCollectionBase::IterPtr
+RRsetCollection::getBeginning() {
+    CollectionMap::iterator it = rrsets_.begin();
+    return (RRsetCollectionBase::IterPtr(new DnsIter(it)));
+}
+
+RRsetCollectionBase::IterPtr
+RRsetCollection::getEnd() {
+    CollectionMap::iterator it = rrsets_.end();
+    return (RRsetCollectionBase::IterPtr(new DnsIter(it)));
+}
+
+} // end of namespace dns
+} // end of namespace isc
diff --git a/src/lib/dns/rrset_collection.h b/src/lib/dns/rrset_collection.h
new file mode 100644
index 0000000..62dd9a9
--- /dev/null
+++ b/src/lib/dns/rrset_collection.h
@@ -0,0 +1,172 @@
+// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef RRSET_COLLECTION_H
+#define RRSET_COLLECTION_H 1
+
+#include <dns/rrset_collection_base.h>
+#include <dns/rrclass.h>
+
+#include <boost/tuple/tuple.hpp>
+#include <boost/tuple/tuple_comparison.hpp>
+
+#include <map>
+
+namespace isc {
+namespace dns {
+
+/// \brief libdns++ implementation of RRsetCollectionBase using an STL
+/// container.
+class RRsetCollection : public RRsetCollectionBase {
+public:
+    /// \brief Constructor.
+    ///
+    /// This constructor creates an empty collection without any data in
+    /// it. RRsets can be added to the collection with the \c addRRset()
+    /// method.
+    RRsetCollection() {}
+
+    /// \brief Constructor.
+    ///
+    /// The \c origin and \c rrclass arguments are required for the zone
+    /// loading, but \c RRsetCollection itself does not do any
+    /// validation, and the collection of RRsets does not have to form a
+    /// valid zone.
+    ///
+    /// \throws MasterLoaderError if there is an error during loading.
+    /// \param filename Name of a file containing a collection of RRs in
+    /// the master file format (which may or may not form a valid zone).
+    /// \param origin The zone origin.
+    /// \param rrclass The zone class.
+    RRsetCollection(const char* filename, const isc::dns::Name& origin,
+                    const isc::dns::RRClass& rrclass);
+
+    /// \brief Constructor.
+    ///
+    /// This constructor is similar to the previous one, but instead of
+    /// taking a filename to load a zone from, it takes an input
+    /// stream.
+    ///
+    /// \throws MasterLoaderError if there is an error during loading.
+    /// \param input_stream The input stream to load from.
+    /// \param origin The zone origin.
+    /// \param rrclass The zone class.
+    RRsetCollection(std::istream& input_stream, const isc::dns::Name& origin,
+                    const isc::dns::RRClass& rrclass);
+
+    /// \brief Destructor
+    virtual ~RRsetCollection() {}
+
+    /// \brief Add an RRset to the collection.
+    ///
+    /// Does not do any validation whether \c rrset belongs to a
+    /// particular zone or not. A reference to \c rrset is taken in an
+    /// internally managed \c shared_ptr, so even if the caller's
+    /// \c RRsetPtr is destroyed, the RRset it wrapped is still alive
+    /// and managed by the \c RRsetCollection. It throws an
+    /// \c isc::InvalidParameter exception if an rrset with the same
+    /// class, type and name already exists.
+    ///
+    /// Callers must not modify the RRset after adding it to the
+    /// collection, as the rrset is indexed internally by the
+    /// collection.
+    void addRRset(isc::dns::RRsetPtr rrset);
+
+    /// \brief Remove an RRset from the collection.
+    ///
+    /// RRset(s) matching the \c name, \c rrclass and \c rrtype are
+    /// removed from the collection.
+    ///
+    /// \return \c true if a matching RRset was deleted, \c false if no
+    /// such RRset exists.
+    bool removeRRset(const isc::dns::Name& name,
+                     const isc::dns::RRClass& rrclass,
+                     const isc::dns::RRType& rrtype);
+
+    /// \brief Find a matching RRset in the collection.
+    ///
+    /// Returns the RRset in the collection that exactly matches the
+    /// given \c name, \c rrclass and \c rrtype.  If no matching RRset
+    /// is found, \c NULL is returned.
+    ///
+    /// \param name The name of the RRset to search for.
+    /// \param rrclass The class of the RRset to search for.
+    /// \param rrtype The type of the RRset to search for.
+    /// \return The RRset if found, \c NULL otherwise.
+    virtual isc::dns::ConstRRsetPtr find(const isc::dns::Name& name,
+                                         const isc::dns::RRClass& rrclass,
+                                         const isc::dns::RRType& rrtype) const;
+
+    /// \brief Find a matching RRset in the collection (non-const
+    /// variant).
+    ///
+    /// See above for a description of the method and arguments.
+    isc::dns::RRsetPtr find(const isc::dns::Name& name,
+                            const isc::dns::RRClass& rrclass,
+                            const isc::dns::RRType& rrtype);
+
+private:
+    template<typename T>
+    void constructHelper(T source, const isc::dns::Name& origin,
+                         const isc::dns::RRClass& rrclass);
+    void loaderCallback(const std::string&, size_t, const std::string&);
+
+    typedef boost::tuple<isc::dns::RRClass, isc::dns::RRType, isc::dns::Name>
+        CollectionKey;
+    typedef std::map<CollectionKey, isc::dns::RRsetPtr> CollectionMap;
+
+    CollectionMap rrsets_;
+
+protected:
+    class DnsIter : public RRsetCollectionBase::Iter {
+    public:
+        DnsIter(CollectionMap::iterator& iter) :
+            iter_(iter)
+        {}
+
+        virtual const isc::dns::AbstractRRset& getValue() {
+            isc::dns::RRsetPtr& rrset = iter_->second;
+            return (*rrset);
+        }
+
+        virtual IterPtr getNext() {
+            CollectionMap::iterator it = iter_;
+            ++it;
+            return (RRsetCollectionBase::IterPtr(new DnsIter(it)));
+        }
+
+        virtual bool equals(Iter& other) {
+            const DnsIter* other_real = dynamic_cast<DnsIter*>(&other);
+            if (other_real == NULL) {
+                return (false);
+            }
+            return (iter_ == other_real->iter_);
+        }
+
+    private:
+        CollectionMap::iterator iter_;
+    };
+
+    virtual RRsetCollectionBase::IterPtr getBeginning();
+    virtual RRsetCollectionBase::IterPtr getEnd();
+};
+
+} // end of namespace dns
+} // end of namespace isc
+
+#endif  // RRSET_COLLECTION_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/dns/rrset_collection_base.h b/src/lib/dns/rrset_collection_base.h
new file mode 100644
index 0000000..27e46d1
--- /dev/null
+++ b/src/lib/dns/rrset_collection_base.h
@@ -0,0 +1,163 @@
+// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef RRSET_COLLECTION_BASE_H
+#define RRSET_COLLECTION_BASE_H 1
+
+#include <dns/rrset.h>
+#include <dns/name.h>
+
+#include <boost/shared_ptr.hpp>
+
+#include <iterator>
+
+namespace isc {
+namespace dns {
+
+/// \brief Generic class to represent a set of RRsets.
+///
+/// This is a generic container and the stored set of RRsets does not
+/// necessarily form a valid zone (e.g. there doesn't necessarily have
+/// to be an SOA at the "origin"). Instead, it will be used to represent
+/// a single zone for the purpose of zone loading/checking. It provides
+/// a simple find() method to find an RRset for the given name and type
+/// (and maybe class) and a way to iterate over all RRsets.
+///
+/// See \c RRsetCollection for a simple libdns++ implementation using an
+/// STL container. libdatasrc will have another implementation.
+class RRsetCollectionBase {
+public:
+    /// \brief Find a matching RRset in the collection.
+    ///
+    /// Returns the RRset in the collection that exactly matches the
+    /// given \c name, \c rrclass and \c rrtype.  If no matching RRset
+    /// is found, \c NULL is returned.
+    ///
+    /// \param name The name of the RRset to search for.
+    /// \param rrtype The type of the RRset to search for.
+    /// \param rrclass The class of the RRset to search for.
+    /// \return The RRset if found, \c NULL otherwise.
+    virtual isc::dns::ConstRRsetPtr find
+        (const isc::dns::Name& name, const isc::dns::RRClass& rrclass,
+         const isc::dns::RRType& rrtype)
+        const = 0;
+
+    /// \brief Destructor
+    virtual ~RRsetCollectionBase() {}
+
+protected:
+    class Iter; // forward declaration
+
+    /// \brief Wraps Iter with a reference count.
+    typedef boost::shared_ptr<Iter> IterPtr;
+
+    /// \brief A helper iterator interface for \c RRsetCollectionBase.
+    ///
+    /// This is a protected iterator class that is a helper interface
+    /// used by the public iterator.  Derived classes of
+    /// \c RRsetCollectionBase are supposed to implement this class and
+    /// the \c getBeginning() and \c getEnd() methods, so that the
+    /// public interator interface can be provided. This is a forward
+    /// iterator only.
+    class Iter {
+    public:
+        /// \brief Returns the \c AbstractRRset currently pointed to by
+        /// the iterator.
+        virtual const isc::dns::AbstractRRset& getValue() = 0;
+
+        /// \brief Returns an \c IterPtr wrapping an Iter pointing to
+        /// the next \c AbstractRRset in sequence in the collection.
+        virtual IterPtr getNext() = 0;
+
+        /// \brief Check if another iterator is equal to this one.
+        ///
+        /// Returns \c true if this iterator is equal to \c other,
+        /// \c false otherwise. Note that if \c other is not the same
+        /// type as \c this, or cannot be compared meaningfully, the
+        /// method must return \c false.
+        ///
+        /// \param other The other iterator to compare against.
+        /// \return \c true if equal, \c false otherwise.
+        virtual bool equals(Iter& other) = 0;
+    };
+
+    /// \brief Returns an \c IterPtr wrapping an Iter pointing to the
+    /// beginning of the collection.
+    virtual IterPtr getBeginning() = 0;
+
+    /// \brief Returns an \c IterPtr wrapping an Iter pointing past the
+    /// end of the collection.
+    virtual IterPtr getEnd() = 0;
+
+public:
+    /// \brief A forward \c std::iterator for \c RRsetCollectionBase.
+    ///
+    /// It behaves like a \c std::iterator forward iterator, so please
+    /// see its documentation for usage.
+    class Iterator : std::iterator<std::forward_iterator_tag,
+                                   const isc::dns::AbstractRRset>
+    {
+    public:
+        explicit Iterator(IterPtr iter) :
+            iter_(iter)
+        {}
+
+        reference operator*() {
+            return (iter_->getValue());
+        }
+
+        Iterator& operator++() {
+            iter_ = iter_->getNext();
+            return (*this);
+        }
+
+        Iterator operator++(int) {
+            Iterator tmp(iter_);
+            ++*this;
+            return (tmp);
+        }
+
+        bool operator==(const Iterator& other) const {
+            return (iter_->equals(*other.iter_));
+        }
+
+        bool operator!=(const Iterator& other) const {
+            return (!iter_->equals(*other.iter_));
+        }
+
+    private:
+        IterPtr iter_;
+    };
+
+    /// \brief Returns an iterator pointing to the beginning of the
+    /// collection.
+    Iterator begin() {
+      return Iterator(getBeginning());
+    }
+
+    /// \brief Returns an iterator pointing past the end of the
+    /// collection.
+    Iterator end() {
+      return Iterator(getEnd());
+    }
+};
+
+} // end of namespace dns
+} // end of namespace isc
+
+#endif  // RRSET_COLLECTION_BASE_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/dns/tests/Makefile.am b/src/lib/dns/tests/Makefile.am
index df42720..d71ec13 100644
--- a/src/lib/dns/tests/Makefile.am
+++ b/src/lib/dns/tests/Makefile.am
@@ -75,6 +75,7 @@ run_unittests_SOURCES += tsigkey_unittest.cc
 run_unittests_SOURCES += tsigrecord_unittest.cc
 run_unittests_SOURCES += character_string_unittest.cc
 run_unittests_SOURCES += master_loader_callbacks_test.cc
+run_unittests_SOURCES += rrset_collection_unittest.cc
 run_unittests_SOURCES += run_unittests.cc
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 # We shouldn't need to include BOTAN_LIBS here, but there
diff --git a/src/lib/dns/tests/rrset_collection_unittest.cc b/src/lib/dns/tests/rrset_collection_unittest.cc
new file mode 100644
index 0000000..e17e9e7
--- /dev/null
+++ b/src/lib/dns/tests/rrset_collection_unittest.cc
@@ -0,0 +1,246 @@
+// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <dns/rrset_collection.h>
+#include <dns/rrttl.h>
+#include <dns/rdataclass.h>
+
+#include <gtest/gtest.h>
+
+#include <list>
+#include <fstream>
+
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+using namespace std;
+
+namespace {
+
+class RRsetCollectionTest : public ::testing::Test {
+public:
+    RRsetCollectionTest() :
+        rrclass("IN"),
+        origin("example.org"),
+        collection(TEST_DATA_SRCDIR "/example.org", origin, rrclass)
+    {}
+
+    const RRClass rrclass;
+    const Name origin;
+    RRsetCollection collection;
+};
+
+TEST_F(RRsetCollectionTest, istreamConstructor) {
+    std::ifstream fs(TEST_DATA_SRCDIR "/example.org");
+    RRsetCollection collection2(fs, origin, rrclass);
+
+    RRsetCollectionBase::Iterator iter = collection.begin();
+    RRsetCollectionBase::Iterator iter2 = collection2.begin();
+    while (iter != collection.end()) {
+         ASSERT_TRUE(iter2 != collection2.end());
+         EXPECT_EQ((*iter).toText(), (*iter2).toText());
+         ++iter;
+         ++iter2;
+    }
+    ASSERT_TRUE(iter2 == collection2.end());
+}
+
+template <typename T, typename TP>
+void doFind(T& collection, const RRClass& rrclass) {
+    // Test the find() that returns ConstRRsetPtr
+    TP rrset = collection.find(Name("www.example.org"), rrclass, RRType::A());
+    EXPECT_TRUE(rrset);
+    EXPECT_EQ(RRType::A(), rrset->getType());
+    EXPECT_EQ(RRTTL(3600), rrset->getTTL());
+    EXPECT_EQ(RRClass("IN"), rrset->getClass());
+    EXPECT_EQ(Name("www.example.org"), rrset->getName());
+
+    // foo.example.org doesn't exist
+    rrset = collection.find(Name("foo.example.org"), rrclass, RRType::A());
+    EXPECT_FALSE(rrset);
+
+    // www.example.org exists, but not with MX
+    rrset = collection.find(Name("www.example.org"), rrclass, RRType::MX());
+    EXPECT_FALSE(rrset);
+
+    // www.example.org exists, with AAAA
+    rrset = collection.find(Name("www.example.org"), rrclass, RRType::AAAA());
+    EXPECT_TRUE(rrset);
+
+    // www.example.org with AAAA does not exist in RRClass::CH()
+    rrset = collection.find(Name("www.example.org"), RRClass::CH(),
+                            RRType::AAAA());
+    EXPECT_FALSE(rrset);
+}
+
+TEST_F(RRsetCollectionTest, findConst) {
+    // Test the find() that returns ConstRRsetPtr
+    const RRsetCollection& ccln = collection;
+    doFind<const RRsetCollection, ConstRRsetPtr>(ccln, rrclass);
+}
+
+TEST_F(RRsetCollectionTest, find) {
+    // Test the find() that returns RRsetPtr
+    doFind<RRsetCollection, RRsetPtr>(collection, rrclass);
+}
+
+void
+doAddAndRemove(RRsetCollection& collection, const RRClass& rrclass) {
+    // foo.example.org/A doesn't exist
+    RRsetPtr rrset_found = collection.find(Name("foo.example.org"), rrclass,
+                                           RRType::A());
+    EXPECT_FALSE(rrset_found);
+
+    // Add foo.example.org/A
+    RRsetPtr rrset(new BasicRRset(Name("foo.example.org"), rrclass, RRType::A(),
+                                  RRTTL(7200)));
+    rrset->addRdata(in::A("192.0.2.1"));
+    collection.addRRset(rrset);
+
+    // foo.example.org/A should now exist
+    rrset_found = collection.find(Name("foo.example.org"), rrclass,
+                                  RRType::A());
+    EXPECT_TRUE(rrset_found);
+    EXPECT_EQ(RRType::A(), rrset_found->getType());
+    EXPECT_EQ(RRTTL(7200), rrset_found->getTTL());
+    EXPECT_EQ(RRClass("IN"), rrset_found->getClass());
+    EXPECT_EQ(Name("foo.example.org"), rrset_found->getName());
+
+    // The collection must not be empty.
+    EXPECT_TRUE(collection.end() != collection.begin());
+
+    // Adding a duplicate RRset must throw.
+    EXPECT_THROW({
+        collection.addRRset(rrset);
+    }, isc::InvalidParameter);
+
+    // Remove foo.example.org/A, which should pass
+    EXPECT_TRUE(collection.removeRRset(Name("foo.example.org"),
+                                       rrclass, RRType::A()));
+    // foo.example.org/A should not exist now
+    rrset_found = collection.find(Name("foo.example.org"), rrclass,
+                                  RRType::A());
+    EXPECT_FALSE(rrset_found);
+
+    // Removing foo.example.org/A should fail now
+    EXPECT_FALSE(collection.removeRRset(Name("foo.example.org"),
+                                        rrclass, RRType::A()));
+}
+
+TEST_F(RRsetCollectionTest, addAndRemove) {
+    doAddAndRemove(collection, rrclass);
+}
+
+TEST_F(RRsetCollectionTest, empty) {
+    RRsetCollection cln;
+
+    // Here, cln is empty.
+    EXPECT_TRUE(cln.end() == cln.begin());
+
+    doAddAndRemove(cln, rrclass);
+
+    // cln should be empty again here, after the add and remove
+    // operations.
+    EXPECT_TRUE(cln.end() == cln.begin());
+}
+
+TEST_F(RRsetCollectionTest, iteratorTest) {
+    // The collection must not be empty.
+    EXPECT_TRUE(collection.end() != collection.begin());
+
+    // Here, we just count the records and do some basic tests on them.
+    size_t count = 0;
+    for (RRsetCollection::Iterator it = collection.begin();
+         it != collection.end(); ++it) {
+         ++count;
+         const AbstractRRset& rrset = *it;
+         EXPECT_EQ(rrclass, rrset.getClass());
+         EXPECT_EQ(RRTTL(3600), rrset.getTTL());
+    }
+
+    // example.org master file has SOA, NS, A, AAAA
+    EXPECT_EQ(4, count);
+}
+
+// This is a dummy class which is used in iteratorCompareDifferent test
+// to compare iterators from different RRsetCollectionBase
+// implementations.
+class MyRRsetCollection : public RRsetCollectionBase {
+public:
+    MyRRsetCollection()
+    {}
+
+    virtual isc::dns::ConstRRsetPtr find(const isc::dns::Name&,
+                                         const isc::dns::RRClass&,
+                                         const isc::dns::RRType&) const {
+        return (ConstRRsetPtr());
+    }
+
+    typedef std::list<isc::dns::RRset> MyCollection;
+
+protected:
+    class MyIter : public RRsetCollectionBase::Iter {
+    public:
+        MyIter(MyCollection::iterator& iter) :
+            iter_(iter)
+        {}
+
+        virtual const isc::dns::AbstractRRset& getValue() {
+            return (*iter_);
+        }
+
+        virtual IterPtr getNext() {
+            MyCollection::iterator it = iter_;
+            ++it;
+            return (RRsetCollectionBase::IterPtr(new MyIter(it)));
+        }
+
+        virtual bool equals(Iter& other) {
+            const MyIter* other_real = dynamic_cast<MyIter*>(&other);
+            if (other_real == NULL) {
+                return (false);
+            }
+            return (iter_ == other_real->iter_);
+        }
+
+    private:
+        MyCollection::iterator iter_;
+    };
+
+    virtual RRsetCollectionBase::IterPtr getBeginning() {
+        MyCollection::iterator it = dummy_list_.begin();
+        return (RRsetCollectionBase::IterPtr(new MyIter(it)));
+    }
+
+    virtual RRsetCollectionBase::IterPtr getEnd() {
+        MyCollection::iterator it = dummy_list_.end();
+        return (RRsetCollectionBase::IterPtr(new MyIter(it)));
+    }
+
+private:
+    MyCollection dummy_list_;
+};
+
+TEST_F(RRsetCollectionTest, iteratorCompareDifferent) {
+    // Create objects of two different RRsetCollectionBase
+    // implementations.
+    RRsetCollection cln1;
+    MyRRsetCollection cln2;
+
+    // Comparing two iterators from different RRsetCollectionBase
+    // implementations must not throw.
+    EXPECT_TRUE(cln2.begin() != cln1.begin());
+    EXPECT_TRUE(cln1.end() != cln2.end());
+}
+
+} // namespace



More information about the bind10-changes mailing list