[svn] commit: r41 - in /experiments/jinmei-messageapi: Makefile dnsexceptions.hh dnsmessage-test.cc dnsmessage.cc dnsmessage.hh dnsname.cc dnsname.hh rrset-test.cc rrset.cc rrset.hh

BIND 10 source code commits bind10-changes at lists.isc.org
Wed Sep 30 08:29:11 UTC 2009


Author: jinmei
Date: Wed Sep 30 08:29:10 2009
New Revision: 41

Log:
an initial prototyping of the DNS message API.
the test program can send a simple DNS query using the API.

Added:
    experiments/jinmei-messageapi/dnsmessage-test.cc
    experiments/jinmei-messageapi/dnsmessage.cc
    experiments/jinmei-messageapi/dnsmessage.hh
Modified:
    experiments/jinmei-messageapi/Makefile
    experiments/jinmei-messageapi/dnsexceptions.hh
    experiments/jinmei-messageapi/dnsname.cc
    experiments/jinmei-messageapi/dnsname.hh
    experiments/jinmei-messageapi/rrset-test.cc
    experiments/jinmei-messageapi/rrset.cc
    experiments/jinmei-messageapi/rrset.hh

Modified: experiments/jinmei-messageapi/Makefile
==============================================================================
--- experiments/jinmei-messageapi/Makefile (original)
+++ experiments/jinmei-messageapi/Makefile Wed Sep 30 08:29:10 2009
@@ -1,7 +1,7 @@
 CC = g++
 CFLAGS = -g -Wall
 BOOSTINCFLAG = -I. -I/usr/pkg/include -I/usr/local/include	#define this appropriately
-TARGET = dnsname-test rrset-test
+TARGET = dnsname-test rrset-test dnsmessage-test
 
 .cc.o:
 	$(CC) $(CFLAGS) $(BOOSTINCFLAG) -c $<
@@ -14,6 +14,9 @@
 rrset-test: rrset.o dnsname.o rrset-test.o
 	$(CC) rrset.o dnsname.o rrset-test.o -o $@
 
+dnsmessage-test: rrset.o dnsname.o dnsmessage.o dnsmessage-test.o
+	$(CC) dnsmessage.o rrset.o dnsname.o dnsmessage-test.o -o $@
+
 ##
 clean:
 	/bin/rm -f $(TARGET) *.o *.~ 

Modified: experiments/jinmei-messageapi/dnsexceptions.hh
==============================================================================
--- experiments/jinmei-messageapi/dnsexceptions.hh (original)
+++ experiments/jinmei-messageapi/dnsexceptions.hh Wed Sep 30 08:29:10 2009
@@ -29,6 +29,10 @@
         class DNSInvalidRdataType : public DNSException {};
         class DNSRdtypeMismatch : public DNSException {};
         class DNSInvalidWireRdata : public DNSException {};
+        class DNSNoMessageRenderer : public DNSException {};
+        class DNSNoNameCompressor : public DNSException {};
+        class DNSInvalidMessageSection : public DNSException {};
+        class DNSInvalidRendererPosition : public DNSException {};
     }
 }
 #endif  // __DNSEXCEPTIONS_HH

Modified: experiments/jinmei-messageapi/dnsname.cc
==============================================================================
--- experiments/jinmei-messageapi/dnsname.cc (original)
+++ experiments/jinmei-messageapi/dnsname.cc Wed Sep 30 08:29:10 2009
@@ -17,6 +17,7 @@
 #include <stdexcept>
 
 #include "dnsname.hh"
+#include "dnsmessage.hh"
 #include "dnsexceptions.hh"
 
 using namespace std;
@@ -282,7 +283,7 @@
 }
 
 string
-Name::to_string(bool omit_final_dot) const
+Name::to_text(bool omit_final_dot) const
 {
     string tdata;
     unsigned int nlen;
@@ -398,6 +399,14 @@
     return (tdata);
 }
 
+void
+Name::to_wire(MessageRenderer& r, NameCompressor& c) const
+{
+    // TBD: very simple version for prototyping; e.g. it omits compression.
+    r.write_data(_ndata.c_str(), _ndata.size());
+    r.write_uint8(0);           // XXX: explicitly need trailing null char
+}
+
 bool
 Name::operator==(const Name &other) const
 {
@@ -453,6 +462,6 @@
 ostream &
 operator<<(ostream &os, const Name &name)
 {
-    os << name.to_string(false);
+    os << name.to_text(false);
     return (os);
 }

Modified: experiments/jinmei-messageapi/dnsname.hh
==============================================================================
--- experiments/jinmei-messageapi/dnsname.hh (original)
+++ experiments/jinmei-messageapi/dnsname.hh Wed Sep 30 08:29:10 2009
@@ -26,67 +26,73 @@
 using namespace std;
 
 namespace ISC {
-    namespace DNS {
-        typedef enum {
-            namereln_none = 0,
-            namereln_contains = 1,
-            namereln_subdomain = 2,
-            namereln_equal = 3,
-            namereln_commonancestor = 4
-        } NameRelation;
-        class NameComparisonResult {
-        public:
-            explicit NameComparisonResult(int order, int nlabels,
-                                          NameRelation reln) :
-                _order(order), _nlabels(nlabels), _reln(reln)
-            {}
-            int order() const { return (_order); }
-            int nlabels() const { return (_nlabels); }
-            NameRelation reln() const { return (_reln); }
-        private:
-            int _order;
-            int _nlabels;
-            NameRelation _reln;
-        };
-        class Name {
-        public:
-            // constructors
-            Name();
-            explicit Name(const string &namestr);
-            // need a ctor for "from-wire"?  how can we
-            // differentiate it with "from-string" (above)?
-            // copy constructor (default cp-ctor should work fine)
-            //Name(const Name &orig);
-            // destructor (default dtor should work fine)
-            //~Name();
+namespace DNS {
+class MessageRenderer;
+class NameCompressor;
 
-            // public methods
-            string to_string(bool omit_final_dot) const;
-            unsigned int countlabels() const { return (_labels); }
-            NameComparisonResult fullcompare(const Name &other) const;
-            Name split(unsigned int first, unsigned int n) const;
-            Name concatenate(const Name &suffix) const;
-            bool is_wildcard() const;
-            bool is_absolute() const;
-            bool operator==(const Name &other) const;
-            bool operator!=(const Name &other) const
-            {
-                return (!(*this == other));
-            }
-            bool operator<=(const Name &other) const;
-            bool operator>=(const Name &other) const;
-            bool operator<(const Name &other) const;
-            bool operator>(const Name &other) const;
-        private:
-            string _ndata; // or vector<unsigned char>?
-            vector<char> _offsets;
-            unsigned int _length;
-            unsigned int _labels;
-            bool _is_absolute;
+typedef enum {
+    namereln_none = 0,
+    namereln_contains = 1,
+    namereln_subdomain = 2,
+    namereln_equal = 3,
+    namereln_commonancestor = 4
+} NameRelation;
+class NameComparisonResult {
+public:
+    explicit NameComparisonResult(int order, int nlabels,
+                                  NameRelation reln) :
+        _order(order), _nlabels(nlabels), _reln(reln)
+    {}
+    int order() const { return (_order); }
+    int nlabels() const { return (_nlabels); }
+    NameRelation reln() const { return (_reln); }
+private:
+    int _order;
+    int _nlabels;
+    NameRelation _reln;
+};
+class Name {
+public:
+    // constructors
+    Name();
+    explicit Name(const string &namestr);
+    // need a ctor for "from-wire"?  how can we differentiate it with
+    // "from-string" (above)?
 
-            void from_string(const string &namestr);
-        };
+    // copy constructor (default cp-ctor should work fine)
+    //Name(const Name &orig);
+
+    // destructor (default dtor should work fine)
+    //~Name();
+
+    // public methods
+    string to_text(bool omit_final_dot) const;
+    void to_wire(MessageRenderer& r, NameCompressor& c) const;
+    unsigned int countlabels() const { return (_labels); }
+    NameComparisonResult fullcompare(const Name &other) const;
+    Name split(unsigned int first, unsigned int n) const;
+    Name concatenate(const Name &suffix) const;
+    bool is_wildcard() const;
+    bool is_absolute() const;
+    bool operator==(const Name &other) const;
+    bool operator!=(const Name &other) const
+    {
+        return (!(*this == other));
     }
+    bool operator<=(const Name &other) const;
+    bool operator>=(const Name &other) const;
+    bool operator<(const Name &other) const;
+    bool operator>(const Name &other) const;
+private:
+    string _ndata; // or vector<unsigned char>?
+    vector<char> _offsets;
+    unsigned int _length;
+    unsigned int _labels;
+    bool _is_absolute;
+
+    void from_string(const string &namestr);
+};
+}
 }
 
 ostream &operator<<(ostream &os, const ISC::DNS::Name &name);

Modified: experiments/jinmei-messageapi/rrset-test.cc
==============================================================================
--- experiments/jinmei-messageapi/rrset-test.cc (original)
+++ experiments/jinmei-messageapi/rrset-test.cc Wed Sep 30 08:29:10 2009
@@ -40,33 +40,27 @@
     cout << (numericRdtype == RdataType::AAAA) << endl; // should be 1
 
     AAAARdata aaaa("2001:0db8:0000:0000:0000:0000:0000:1234");
-    cout << aaaa.toText() << endl; // should be (e.g.) "2001:db8::1234"
+    cout << aaaa.to_text() << endl; // should be (e.g.) "2001:db8::1234"
 
-    // Construct a AAAA rdataset and print it.
-    RdataSet rdataset(RdataClass::IN, RdataType::AAAA, 3600);
-    rdataset.addRdata(rdataptr_t(new AAAARdata("2001:db8::1234")));
-    rdataset.addRdata(rdataptr_t(new AAAARdata("2001:db8::abcd")));
-    cout << rdataset.toText() << endl; // "<TTL> IN AAAA <addr>"
-    cout << rdataset.countRdata() << endl; // should be 2
+    // Construct a AAAA RRset and print it.
+    RRSet rrset(Name("www.example.com."), RdataClass::IN, RdataType::AAAA,
+                3600);
+    rrset.add_rdata(rdataptr_t(new AAAARdata("2001:db8::1234")));
+    rrset.add_rdata(rdataptr_t(new AAAARdata("2001:db8::abcd")));
+    cout << rrset.to_text() << endl; // "<name> <TTL> IN AAAA <addr>"
+    cout << rrset.count_rdata() << endl; // should be 2
 
-    // Construct a AAAA RRset, using the rdataset just created above and a
-    // name, and print it.
-    RRSet rrset(Name("www.example.com."), rdataset);
-    rrset.addRdata(rdataptr_t(new AAAARdata("2001:db8::beef")));
-    cout << rrset.toText() << endl; // "<name> <TTL> IN AAAA <addr>"
-    cout << rrset.countRdata() << endl; // should be 3
-
-    // An example use case of examining each rdata in an RRset (or rdataset)
-    vector<AAAARdata> datalist = rrset.getRdatalist<AAAARdata>();
+    // An example use case of examining each rdata in an RRset
+    vector<AAAARdata> datalist;
+    rrset.get_rdatalist(datalist);
     for (vector<AAAARdata>::const_iterator it = datalist.begin();
          it != datalist.end();
          ++it)
     {
-        char addrbuf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:"
-                            "255.255.255.255")];
-        inet_ntop(AF_INET6, &(*it).getAddress(), addrbuf,
-                  sizeof(addrbuf)); // omit error check for brevity
-        cout << addrbuf << endl;
+        char addrbuf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
+        // omit error check for brevity:
+        inet_ntop(AF_INET6, &(*it).getAddress(), addrbuf, sizeof(addrbuf));
+        cout << addrbuf << endl;    // 2001:db8::{1234, abcd}
     }
 
     return (0);

Modified: experiments/jinmei-messageapi/rrset.cc
==============================================================================
--- experiments/jinmei-messageapi/rrset.cc (original)
+++ experiments/jinmei-messageapi/rrset.cc Wed Sep 30 08:29:10 2009
@@ -23,6 +23,7 @@
 #include <cstring>
 
 #include "rrset.hh"
+#include "dnsmessage.hh"
 
 using namespace std;
 using namespace ISC::DNS;
@@ -40,7 +41,7 @@
 }
 
 const string
-RdataClass::toText() const
+RdataClass::to_text() const
 {
     // XXX: quick hack
     if (_classval == 1)
@@ -48,6 +49,12 @@
     else if (_classval == 3)
         return ("CHAOS");
     throw runtime_error("unexpected case");
+}
+
+void
+RdataClass::to_wire(MessageRenderer& r) const
+{
+    r.write_uint16(_classval);
 }
 
 const RdataClass RdataClass::IN("IN");
@@ -66,7 +73,7 @@
 }
 
 const string
-RdataType::toText() const
+RdataType::to_text() const
 {
     if (_typeval == 1)
         return ("A");
@@ -75,10 +82,22 @@
     throw runtime_error("unexpected case");
 }
 
+void
+RdataType::to_wire(MessageRenderer& r) const
+{
+    r.write_uint16(_typeval);
+}
+
 const RdataType RdataType::A("A");
 const RdataType RdataType::AAAA("AAAA");
 // ...more to follow
 
+void
+TTL::to_wire(MessageRenderer& r) const
+{
+    r.write_uint16(_ttlval);
+}
+
 ARdata::ARdata(const string& addrstr)
 {
     if (inet_pton(AF_INET, addrstr.c_str(), &_addr) != 1)
@@ -86,21 +105,21 @@
 }
 
 void
-ARdata::fromWire(const string& wireData)
+ARdata::from_wire(const string& wireData)
 {
     if (wireData.size() != sizeof(_addr))
         throw DNSInvalidWireRdata();
     memcpy(&_addr, wireData.data(), sizeof(_addr));
 }
 
-string
-ARdata::toWire() const
-{
-    return (string((const char *)&_addr, sizeof(_addr))); // XXX ugly
-}
-
-string
-ARdata::toText() const
+void
+ARdata::to_wire(MessageRenderer& renderer, NameCompressor& compressor) const
+{
+    //TBD: copy (const char *)&_addr, sizeof(_addr)
+}
+
+string
+ARdata::to_text() const
 {
     char addrbuf[sizeof("255.255.255.255")];
 
@@ -117,21 +136,21 @@
 }
 
 void
-AAAARdata::fromWire(const string& wireData)
+AAAARdata::from_wire(const string& wireData)
 {
     if (wireData.size() != sizeof(_addr))
         throw DNSInvalidWireRdata();
     memcpy(&_addr, wireData.data(), sizeof(_addr));
 }
 
-string
-AAAARdata::toWire() const
-{
-    return (string((const char *)&_addr, sizeof(_addr))); // XXX
-}
-
-string
-AAAARdata::toText() const
+void
+AAAARdata::to_wire(MessageRenderer& renderer, NameCompressor& compressor) const
+{
+    //TBD: copy (const char *)&_addr, sizeof(_addr)
+}
+
+string
+AAAARdata::to_text() const
 {
     char addrbuf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
 
@@ -142,15 +161,15 @@
 }
 
 void
-RdataSet::addRdata(rdataptr_t rdata)
-{
-    if (rdata->getType() != _rdtype)
+RdataSet::add_rdata(rdataptr_t rdata)
+{
+    if (rdata->get_type() != _rdtype)
         throw DNSRdtypeMismatch();
     _rdatalist.push_back(rdata);
 }
 
 string
-RdataSet::toTextInternal(const string &prefix) const
+RdataSet::to_text() const
 {
     string s;
 
@@ -160,11 +179,98 @@
     {
         if (!s.empty())
             s.push_back('\n');
-        if (!prefix.empty())
-            s += prefix + " ";
-        s += _ttl.toText() + " " + _rdclass.toText() + " " +
-            _rdtype.toText() + " " + (**it).toText();
+        s += _ttl.to_text() + " " + _rdclass.to_text() + " " +
+            _rdtype.to_text() + " " + (**it).to_text();
     }
 
     return (s);
 }
+
+string
+RRSet::to_text() const
+{
+    string s;
+
+    for (vector<rdataptr_t>::const_iterator it = _rdatalist.begin();
+         it != _rdatalist.end();
+         ++it)
+    {
+        if (!s.empty())
+            s.push_back('\n');
+        s += _name.to_text(false) + " ";
+        s += _ttl.to_text() + " " + _rdclass.to_text() + " " +
+            _rdtype.to_text() + " " + (**it).to_text();
+    }
+
+    return (s);
+}
+
+void
+RRSet::add_rdata(rdataptr_t rdata)
+{
+    if (rdata->get_type() != _rdtype)
+        throw DNSRdtypeMismatch();
+    _rdatalist.push_back(rdata);
+}
+
+int
+RRSet::to_wire(Message& message, section_t section)
+{
+    int num_rrs = 0;
+
+    // sort Rdata list based on rrset-order and sortlist, and possible
+    // other options.  Details to be considered.
+
+    MessageRenderer& r = message.get_renderer();
+    NameCompressor& c = message.get_compressor();
+    for (vector<rdataptr_t>::iterator it = _rdatalist.begin();
+         it != _rdatalist.end();
+         ++it, ++num_rrs)
+    {
+        _name.to_wire(r, c);
+        _rdtype.to_wire(r);
+        _rdclass.to_wire(r);
+        _ttl.to_wire(r);
+        (**it).to_wire(r, c);
+
+        // TBD: handle truncation case
+    }
+
+    return (num_rrs);
+}
+
+string
+Question::to_text() const
+{
+    // return in dig-style format.  note that in the wire format class follows
+    // type.
+    return (_name.to_text(false) + " " + _rdclass.to_text() + " " +
+            _rdtype.to_text());
+}
+
+int
+Question::to_wire(Message& message, section_t section)
+{
+    MessageRenderer& r = message.get_renderer();
+    NameCompressor& c = message.get_compressor();
+
+    _name.to_wire(r, c);
+    _rdtype.to_wire(r);
+    _rdclass.to_wire(r);
+
+    return (1);
+}
+
+#ifdef notyet
+void
+SpecialRRSet::to_wire(Message& message)
+{
+    // sort Rdata list based on rrset-order and sortlist, and possible
+    // other options with no or fewer copies.  Details to be considered.
+
+    MessageRenderer& r = message.get_renderer();
+
+    // directly copy or link to wire-formatted data in the renderer for
+    // faster rendering.  details to be considered.
+}
+#endif

Modified: experiments/jinmei-messageapi/rrset.hh
==============================================================================
--- experiments/jinmei-messageapi/rrset.hh (original)
+++ experiments/jinmei-messageapi/rrset.hh Wed Sep 30 08:29:10 2009
@@ -33,273 +33,310 @@
 using namespace std;
 
 namespace ISC {
-    namespace DNS {
-        // if we worry about data copy, we may have to use
-        // shared pointers at the cost of depending on boost.
-        class Rdata;
-        typedef boost::shared_ptr<Rdata> rdataptr_t;
-        // if we want to avoid the dependency, use this; but we'll have
-        // to care much more about resource leak.
-        //typedef Rdata * rdataptr_t;
-
-        class RdataClass {
-        public:
-            RdataClass() {}
-            explicit RdataClass(uint16_t classval) :
-                _classval(classval) {}
-            explicit RdataClass(const string& classstr);
-            const string toText() const;
-            uint16_t toValue() const { return (_classval); }
-            bool operator==(const RdataClass& other) const
-            { return (_classval == other._classval); }
-            bool operator!=(const RdataClass& other) const
-            { return (_classval != other._classval); }
-
-            // (Some) well-known Rdclass constants
-            static const RdataClass IN;
-            static const RdataClass CHAOS;
-        private:
-            uint16_t _classval;
-        };
-
-        class RdataType {
-        public:
-            RdataType() {}
-            explicit RdataType(uint16_t typeval) :
-                _typeval(typeval) {}
-            explicit RdataType(const string& typestr);
-            const string toText() const;
-            uint16_t toValue() const { return (_typeval); }
-            bool operator==(const RdataType& other) const
-            { return (_typeval == other._typeval); }
-            bool operator!=(const RdataType& other) const
-            { return (_typeval != other._typeval); }
-
-            // (Some) Well-known Rdtype constants
-            static const RdataType A;
-            static const RdataType AAAA;
-            // more to follow...
-
-        private:
-            uint16_t _typeval;
-        };
-
-        class TTL {
-        public:
-            TTL() {}
-            // we probably want to pass an integer as an argument
-            // of type TTL (e.g., make_rrset(..., 3600), so don't
-            // make the constructor explicit here.
-            TTL(uint32_t ttlval) : _ttlval(ttlval) {}
-            string toText() const
-            { return (boost::lexical_cast<string>(_ttlval)); }
-            uint32_t toValue() { return (_ttlval); }
-            bool operator==(const TTL& other) const
-            { return (_ttlval == other._ttlval); }
-            bool operator!=(const TTL& other) const
-            { return (_ttlval != other._ttlval); }
-            // define the following using serial number arithmetic:
-            bool operator<=(const TTL &other) const;
-            bool operator>=(const TTL &other) const;
-            bool operator<(const TTL &other) const;
-            bool operator>(const TTL &other) const;
-        private:
-            uint32_t _ttlval;
-        };
-
-        // Abstract RDATA class
-        class Rdata {
-        public:
-            virtual ~Rdata() {};
-            virtual unsigned int count() const = 0;
-            virtual const RdataType& getType() const = 0;
-            virtual string toText() const = 0;
-            virtual void fromWire(const string& wireData) = 0;
-            virtual string toWire() const = 0;
-            // need generic method for getting n-th field? c.f. ldns
-            // e.g. string getField(int n);
-        };
-
-        // WireFormat Rdata.
-        // Whether to have this as a separate concrete class is an
-        // open issue.
-        class WireRdata : public Rdata {
-        public:
-            WireRdata() {}
-            explicit WireRdata(const RdataClass& rdclass,
-                               const RdataType& rdtype,
-                               const string& wireData) :
-                _rdclass(rdclass), _rdtype(rdtype),
-                _wireData(wireData) {}
-            // disallow fromWire() for this class by not defining
-            // it.  (should we allow that?)
-            string toWire() const { return (_wireData); }
-            const RdataType& getType() const { return (_rdtype); }
-        private:
-            RdataClass _rdclass;
-            RdataType _rdtype;
-            string _wireData;
-        };
-
-        // Standard DNS Rdata Subclasses
-        class ARdata : public Rdata {
-        public:
-            ARdata() {}
-            // constructor from a textual IPv4 address
-            explicit ARdata(const string& addrstr);
-            unsigned int count() const { return (1); }
-            const RdataType& getType() const
-            { return (RdataType::A); }
-            string toText() const;
-            void fromWire(const string& wireData);
-            string toWire() const;
-            const struct in_addr& getAddress() const
-            { return (_addr); }
-            bool operator==(const ARdata &other) const
-            { return (_addr.s_addr == other._addr.s_addr); }
-            virtual bool operator!=(const ARdata &other) const
-            { return !(*this == other); }
-        private:
-            // XXX: should probably define an "address class"
-            // and use it.
-            struct in_addr _addr;
-        };
-
-        class AAAARdata : public Rdata {
-        public:
-            AAAARdata() {}
-            // constructor from a textual IPv6 address
-            AAAARdata(const string& addrstr);
-            unsigned int count() const { return (1); }
-            string toText() const;
-            const RdataType& getType() const
-            { return (RdataType::AAAA); }
-            void fromWire(const string& wireData);
-            string toWire() const;
-            const struct in6_addr& getAddress() const
-            { return (_addr); }
-            bool operator==(const AAAARdata &other) const
-            {
-                return (IN6_ARE_ADDR_EQUAL(&_addr,
-                                           &other._addr));
-            }
-            virtual bool operator!=(const AAAARdata &other) const
-            { return !(*this == other); }
-        private:
-            // XXX: should probably define an "address class"
-            // and use it.
-            struct in6_addr _addr;
-        };
-
-        // add NSRdata, MXRdata, etc...
-
-        // A set of RDATAs.  This is a primary class internally used
-        // in our major software such as name servers.
-        // Open Issues:
-        //   - add more set-like operations, e.g, merge?
-        //   - add a "sort" method?  "search(find)" method?
-        //   - BIND9 libdns has some special DNSSEC-related methods
-        //     such as addnoqname(), addclosest().  do we need these?
-        //   - need to check duplicate rdata in addrdata()?
-        //   - need a comparison method?  if so, should it compare
-        //     rdata's as a set or as a list (compare each rdata one
-        //     by one)?  ldns has ldns_rr_list_compare(), which takes
-        //     the latter approach (assuming the caller sorts the lists
-        //     beforehand?).
-        class RdataSet {
-        public:
-            RdataSet() {}
-            explicit RdataSet(const RdataClass& rdclass,
-                              const RdataType& rdtype,
-                              const TTL& ttl) :
-                _rdclass(rdclass), _rdtype(rdtype), _ttl(ttl) {}
-            void addRdata(rdataptr_t rdata);
-            void removeRdata(const Rdata& rdata);
-            string toText() const
-            { return (toTextInternal("")); }
-            string toWire() const;
-            unsigned int countRdata() const
-            { return (_rdatalist.size()); }
-            const RdataClass& getClass() const
-            { return (_rdclass); }
-            const RdataType& getType() const { return (_rdtype); }
-            const TTL& getTTL() const { return (_ttl); }
-            template <typename T> vector<T> getRdatalist() const;
-        protected:
-            string toTextInternal(const string& prefix) const;
-        private:
-            RdataClass _rdclass;
-            RdataType _rdtype;
-            TTL _ttl;
-            vector<rdataptr_t> _rdatalist;
-        };
-
-        template <typename T> vector<T>
-        RdataSet::getRdatalist() const
-        {
-            vector<T> ret;
-            vector<rdataptr_t>::const_iterator it;
-            for (it = _rdatalist.begin();
-                 it != _rdatalist.end();
-                 ++it) {
-                T concreateRdata;
-
-                if (concreateRdata.getType() !=
-                    (**it).getType()) {
-                    throw DNSRdtypeMismatch();
-                }
-                concreateRdata.fromWire((**it).toWire());
-                ret.push_back(concreateRdata);
-            }
-            return (ret);
+namespace DNS {
+// if we worry about data copy, we may have to use
+// shared pointers at the cost of depending on boost.
+class Rdata;
+typedef boost::shared_ptr<Rdata> rdataptr_t;
+// if we want to avoid the dependency, use this; but we'll have
+// to care much more about resource leak.
+//typedef Rdata * rdataptr_t;
+class Message;
+class MessageRenderer;
+class NameCompressor;
+
+// XXX: this should be defined somewhere else.
+typedef enum { SECTION_QUESTION = 0,
+               SECTION_ANSWER = 1,
+               SECTION_AUTHORITY = 2,
+               SECTION_ADDITIONAL = 3,
+               SECTION_MAX = 4 } section_t;
+
+class RdataClass {
+public:
+    RdataClass() {}
+    explicit RdataClass(uint16_t classval) :
+        _classval(classval) {}
+    explicit RdataClass(const string& classstr);
+    const string to_text() const;
+    void to_wire(MessageRenderer& r) const;
+    uint16_t get_value() const { return (_classval); }
+    bool operator==(const RdataClass& other) const
+    { return (_classval == other._classval); }
+    bool operator!=(const RdataClass& other) const
+    { return (_classval != other._classval); }
+
+    // (Some) well-known Rdclass constants
+    static const RdataClass IN;
+    static const RdataClass CHAOS;
+private:
+    uint16_t _classval;
+};
+
+class RdataType {
+public:
+    RdataType() {}
+    explicit RdataType(uint16_t typeval) :
+        _typeval(typeval) {}
+    explicit RdataType(const string& typestr);
+    const string to_text() const;
+    void to_wire(MessageRenderer& r) const;
+    uint16_t get_value() const { return (_typeval); }
+    bool operator==(const RdataType& other) const
+    { return (_typeval == other._typeval); }
+    bool operator!=(const RdataType& other) const
+    { return (_typeval != other._typeval); }
+
+    // (Some) Well-known Rdtype constants
+    static const RdataType A;
+    static const RdataType AAAA;
+    // more to follow...
+
+private:
+    uint16_t _typeval;
+};
+
+class TTL {
+public:
+    TTL() {}
+    // we probably want to pass an integer as an argument
+    // of type TTL (e.g., make_rrset(..., 3600), so don't
+    // make the constructor explicit here.
+    TTL(uint32_t ttlval) : _ttlval(ttlval) {}
+    string to_text() const
+    { return (boost::lexical_cast<string>(_ttlval)); }
+    void to_wire(MessageRenderer& r) const;
+    uint32_t get_value() { return (_ttlval); }
+    bool operator==(const TTL& other) const
+    { return (_ttlval == other._ttlval); }
+    bool operator!=(const TTL& other) const
+    { return (_ttlval != other._ttlval); }
+    // define the following using serial number arithmetic:
+    bool operator<=(const TTL &other) const;
+    bool operator>=(const TTL &other) const;
+    bool operator<(const TTL &other) const;
+    bool operator>(const TTL &other) const;
+private:
+    uint32_t _ttlval;
+};
+
+// Abstract RDATA class
+class Rdata {
+public:
+    virtual ~Rdata() {};
+    virtual unsigned int count() const = 0;
+    virtual const RdataType& get_type() const = 0;
+    virtual string to_text() const = 0;
+    virtual void from_wire(const string& wireData) = 0;
+    virtual void to_wire(MessageRenderer& r,
+                         NameCompressor& c) const = 0;
+    // need generic method for getting n-th field? c.f. ldns
+    // e.g. string getField(int n);
+};
+
+// WireFormat Rdata.
+// Whether to have this as a separate concrete class is an
+// open issue.
+class WireRdata : public Rdata {
+public:
+    WireRdata() {}
+    explicit WireRdata(const RdataClass& rdclass,
+                       const RdataType& rdtype,
+                       const string& wireData) :
+        _rdclass(rdclass), _rdtype(rdtype),
+        _wireData(wireData) {}
+    // disallow to/from_wire() for this class by not defining
+    // it.  (should we allow that?)
+    const RdataType& get_type() const { return (_rdtype); }
+private:
+    RdataClass _rdclass;
+    RdataType _rdtype;
+    string _wireData;
+};
+
+// Standard DNS Rdata Subclasses
+class ARdata : public Rdata {
+public:
+    ARdata() {}
+    // constructor from a textual IPv4 address
+    explicit ARdata(const string& addrstr);
+    unsigned int count() const { return (1); }
+    const RdataType& get_type() const { return (RdataType::A); }
+    static const RdataType& get_type_static() { return (RdataType::A); }
+    string to_text() const;
+    void from_wire(const string& wireData);
+    void to_wire(MessageRenderer& r, NameCompressor& c) const;
+    const struct in_addr& getAddress() const
+    { return (_addr); }
+    bool operator==(const ARdata &other) const
+    { return (_addr.s_addr == other._addr.s_addr); }
+    virtual bool operator!=(const ARdata &other) const
+    { return !(*this == other); }
+private:
+    // XXX: should probably define an "address class"
+    // and use it.
+    struct in_addr _addr;
+};
+
+class AAAARdata : public Rdata {
+public:
+    AAAARdata() {}
+    // constructor from a textual IPv6 address
+    AAAARdata(const string& addrstr);
+    unsigned int count() const { return (1); }
+    string to_text() const;
+    const RdataType& get_type() const { return (RdataType::AAAA); }
+    static const RdataType& get_type_static()
+    { return (RdataType::AAAA); }
+    void from_wire(const string& wireData);
+    void to_wire(MessageRenderer& r, NameCompressor& c) const;
+    const struct in6_addr& getAddress() const
+    { return (_addr); }
+    bool operator==(const AAAARdata &other) const
+    { return (IN6_ARE_ADDR_EQUAL(&_addr, &other._addr)); }
+    virtual bool operator!=(const AAAARdata &other) const
+    { return !(*this == other); }
+private:
+    // XXX: should probably define an "address class"
+    // and use it.
+    struct in6_addr _addr;
+};
+
+// add NSRdata, MXRdata, etc...
+
+// A set of RDATAs.  This is a primary class internally used
+// in our major software such as name servers.
+// Open Issues:
+//   - add more set-like operations, e.g, merge?
+//   - add a "sort" method?  "search(find)" method?
+//   - BIND9 libdns has some special DNSSEC-related methods
+//     such as addnoqname(), addclosest().  do we need these?
+//   - need to check duplicate rdata in addrdata()?
+//   - need a comparison method?  if so, should it compare
+//     rdata's as a set or as a list (compare each rdata one
+//     by one)?  ldns has ldns_rr_list_compare(), which takes
+//     the latter approach (assuming the caller sorts the lists
+//     beforehand?).
+class RdataSet {
+public:
+    RdataSet() {}
+    explicit RdataSet(const RdataClass& rdclass,
+                      const RdataType& rdtype,
+                      const TTL& ttl) :
+        _rdclass(rdclass), _rdtype(rdtype), _ttl(ttl) {}
+    void add_rdata(rdataptr_t rdata);
+    void remove_rdata(const Rdata& rdata);
+    string to_text() const;
+    string to_wire() const;
+    unsigned int count_rdata() const { return (_rdatalist.size()); }
+    const RdataClass& get_class() const { return (_rdclass); }
+    const RdataType& get_type() const { return (_rdtype); }
+    const TTL& getTTL() const { return (_ttl); }
+private:
+    RdataClass _rdclass;
+    RdataType _rdtype;
+    TTL _ttl;
+    vector<rdataptr_t> _rdatalist;
+};
+
+// An RRSet.  Conceptually it's a named RdataSet.  A (section
+// of) DNS message would consist of a list of RRSets.
+class AbstractRRSet {
+public:
+    virtual ~AbstractRRSet() {}
+    virtual string to_text() const = 0;
+    virtual int to_wire(Message& message, section_t section) = 0;
+    virtual unsigned int count_rdata() const = 0;
+    virtual const Name& get_name() const = 0;
+    virtual const RdataClass& get_class() const = 0;
+    virtual const RdataType& get_type() const = 0;
+};
+
+class RRSet : public AbstractRRSet {
+public:
+    RRSet() {}
+    explicit RRSet(const Name &name,
+                   const RdataClass &rdclass,
+                   const RdataType &rdtype,
+                   const TTL &ttl) :
+        _name(name), _rdclass(rdclass), _rdtype(rdtype), _ttl(ttl) {}
+    unsigned int count_rdata() const { return (_rdatalist.size()); }
+    void add_rdata(rdataptr_t rdata);
+    void remove_rdata(const Rdata& rdata);
+    string to_text() const;
+    int to_wire(Message& message, section_t section);
+    const Name& get_name() const { return (_name); } 
+    const RdataClass& get_class() const { return (_rdclass); }
+    const RdataType& get_type() const { return (_rdtype); }
+    const TTL& get_ttl() const { return (_ttl); }
+    template <typename T> void get_rdatalist(vector<T>&) const;
+private:
+    Name _name;
+    RdataClass _rdclass;
+    RdataType _rdtype;
+    TTL _ttl;
+    vector<rdataptr_t> _rdatalist;
+};
+
+class Question : public AbstractRRSet { // generic Question section entry
+public:
+    explicit Question(const Name& name, const RdataClass& rdclass,
+             const RdataType& rdtype) :
+        _name(name), _rdclass(rdclass), _rdtype(rdtype) {}
+    string to_text() const;
+    int to_wire(Message& message, section_t section);
+    unsigned int count_rdata() const { return (0); }
+    const Name& get_name() const { return (_name); } 
+    const RdataClass& get_class() const { return (_rdclass); }
+    const RdataType& get_type() const { return (_rdtype); }
+    
+private:
+    Name _name;
+    RdataClass _rdclass;
+    RdataType _rdtype;
+};
+
+// TBD: this interface should be revisited.
+template <typename T>
+void
+RRSet::get_rdatalist(vector<T>& v) const
+{
+    vector<rdataptr_t>::const_iterator it;
+    for (it = _rdatalist.begin(); it != _rdatalist.end(); ++it) {
+        const T& concreteRdata = static_cast<const T&>(**it); // XXX
+        if (T::get_type_static() != (**it).get_type()) {
+            throw DNSRdtypeMismatch();
         }
-
-        // An RRSet.  Conceptually it's a named RdataSet.  A (section
-        // of) DNS message would consist of a list of RRSets.
-        class RRSet : public RdataSet {
-        public:
-            RRSet() {}
-            explicit RRSet(const Name &name,
-                           const RdataClass &rdclass,
-                           const RdataType &rdtype,
-                           const TTL &ttl) :
-                RdataSet(rdclass, rdtype, ttl), _name(name) {}
-            explicit RRSet(const Name &name,
-                           const RdataSet &rdataset) :
-                RdataSet(rdataset), _name(name) {}
-            string toText() const
-            { return (toTextInternal(_name.to_string(false))); }
-            const Name& getName() const { return (_name); } 
-        private:
-            Name _name;
-        };
-
-        // A single RR.  Architecturally this is redundant, but it
-        // would often be convenient if we can handle each RR
-        // separately.
-        // Note: an RR *is-not-a* set, so conceptually it cannot be a
-        // derived class of RdataSet.
-        class RR {
-        public:
-            RR() {}
-            explicit RR(const string& rrstr);
-            explicit RR(const Name &name, const RdataClass &rdclass,
-                        const RdataType &rdtype, const TTL &ttl,
-                        const Rdata &rdata) {}
-            string toText() const
-            { return (_rrset.toText()); }
-            const Name& getName() const
-            { return (_rrset.getName()); }
-            const RdataClass& getClass() const
-            { return (_rrset.getClass()); }
-            const RdataType& getType() const
-            { return (_rrset.getType()); }
-            const TTL& getTTL() const { return (_rrset.getTTL()); }
-        private:
-            // An RR is (could be) actually implemented as an RRSet
-            // containing at most one RR.
-            RRSet _rrset;
-        };
+        v.push_back(concreteRdata);
     }
 }
+
+// A single RR.  Architecturally this is redundant, but it
+// would often be convenient if we can handle each RR
+// separately.
+// Note: an RR *is-not-a* set, so conceptually it cannot be a
+// derived class of RdataSet.
+class RR {
+public:
+    RR() {}
+    explicit RR(const string& rrstr);
+    explicit RR(const Name &name, const RdataClass &rdclass,
+                const RdataType &rdtype, const TTL &ttl,
+                const Rdata &rdata) {}
+    string to_text() const
+    { return (_rrset.to_text()); }
+    const Name& get_name() const
+    { return (_rrset.get_name()); }
+    const RdataClass& get_class() const
+    { return (_rrset.get_class()); }
+    const RdataType& get_type() const
+    { return (_rrset.get_type()); }
+    const TTL& get_ttl() const { return (_rrset.get_ttl()); }
+private:
+    // An RR is (could be) actually implemented as an RRSet
+    // containing at most one RR.
+    RRSet _rrset;
+};
+}
+}
 #endif  // __RRSET_HH




More information about the bind10-changes mailing list