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

BIND 10 source code commits bind10-changes at lists.isc.org
Wed Oct 7 08:38:07 UTC 2009


Author: jinmei
Date: Wed Oct  7 08:38:07 2009
New Revision: 65

Log:
- added message parser
- added a tiny server as a sample

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

Modified: experiments/jinmei-messageapi/Makefile.in
==============================================================================
--- experiments/jinmei-messageapi/Makefile.in (original)
+++ experiments/jinmei-messageapi/Makefile.in Wed Oct  7 08:38:07 2009
@@ -22,14 +22,15 @@
 
 all: $(TARGET)
 
-dnsname-test: dnsname.o dnsname-test.o
-	$(CXX) dnsname.o dnsname-test.o -o $@
+dnsname-test: dnsname.o dnsresult.o dnsname-test.o
+	$(CXX) dnsname.o dnsresult.o dnsname-test.o -o $@
 
-rrset-test: rrset.o dnsname.o rrset-test.o
-	$(CXX) rrset.o dnsname.o rrset-test.o -o $@
+rrset-test: rrset.o dnsname.o dnsresult.o rrset-test.o
+	$(CXX) rrset.o dnsname.o dnsresult.o rrset-test.o -o $@
 
-dnsmessage-test: rrset.o dnsname.o dnsmessage.o dnsmessage-test.o
-	$(CXX) dnsmessage.o rrset.o dnsname.o dnsmessage-test.o -o $@
+dnsmessage-test: rrset.o dnsname.o dnsresult.o dnsmessage.o dnsmessage-test.o iobuffer.o
+	$(CXX) dnsmessage.o rrset.o dnsname.o dnsresult.o iobuffer.o \
+	dnsmessage-test.o -o $@
 
 ##
 clean:

Modified: experiments/jinmei-messageapi/dnsexceptions.hh
==============================================================================
--- experiments/jinmei-messageapi/dnsexceptions.hh (original)
+++ experiments/jinmei-messageapi/dnsexceptions.hh Wed Oct  7 08:38:07 2009
@@ -29,8 +29,9 @@
 class DNSInvalidRdataType : public DNSException {};
 class DNSRdtypeMismatch : public DNSException {};
 class DNSInvalidWireRdata : public DNSException {};
-class DNSNoMessageRenderer : public DNSException {};
+class DNSNoMessageIOBuffer : public DNSException {};
 class DNSNoNameCompressor : public DNSException {};
+class DNSNoNameDecompressor : public DNSException {};
 class DNSNoMessageParser : public DNSException {};
 class DNSInvalidMessageSection : public DNSException {};
 class DNSInvalidRendererPosition : public DNSException {};

Modified: experiments/jinmei-messageapi/dnsmessage-test.cc
==============================================================================
--- experiments/jinmei-messageapi/dnsmessage-test.cc (original)
+++ experiments/jinmei-messageapi/dnsmessage-test.cc Wed Oct  7 08:38:07 2009
@@ -18,6 +18,7 @@
 #include <sys/socket.h>
 #include <netdb.h>
 
+#include <map>
 #include <iostream>
 
 #include "dnsname.hh"
@@ -27,6 +28,81 @@
 using namespace std;
 using namespace ISC::DNS;
 
+static void
+start_server(int s, const struct addrinfo *res)
+{
+    if (bind(s, res->ai_addr, res->ai_addrlen) < 0)
+        return;
+
+    // Create Database
+    map<string, string> a_db, aaaa_db;
+    a_db.insert(pair<string,string>("www.jinmei.org", "149.20.54.162"));
+    aaaa_db.insert(pair<string,string>("www.jinmei.org", "2001:4f8:3:36::162"));
+    a_db.insert(pair<string,string>("www.isc.org", "149.20.64.42"));
+    aaaa_db.insert(pair<string,string>("www.isc.org", "2001:4f8:0:2::d"));
+
+    int cc;
+    struct sockaddr_storage ss;
+    struct sockaddr* sa;
+    socklen_t sa_len;
+
+    while (1) {
+        Message msg;
+
+        sa_len = sizeof(ss);
+        sa = static_cast<struct sockaddr*>((void*)&ss);
+        cc = msg.get_iobuffer().recv_from(s, sa, &sa_len);
+        if (cc > 0) {
+            ISC::ConstResult result = msg.from_wire();
+
+            if (result != ISC::Result::Success) {
+                cerr << "parse failed: " << result->to_text() << endl;
+                continue;
+            }
+
+            cout << "received a message:\n" << msg.to_text() << endl;
+            if (msg.get_section(SECTION_QUESTION).size() != 1)
+                continue;
+
+            msg.make_response();
+            msg.set_aa(true);
+
+            RRSetPtr query = msg.get_section(SECTION_QUESTION)[0];
+            map<string, string>::const_iterator it;
+            rdataptr_t rdatap;
+
+            if (query->get_type() == RdataType::A) {
+                it = a_db.find(query->get_name().to_text(true));
+                if (it != a_db.end()) {
+                    rdatap = rdataptr_t(new ARdata(it->second));
+                }
+            } else if (query->get_type() == RdataType::AAAA) {
+                it = aaaa_db.find(query->get_name().to_text(true));
+                if (it != a_db.end()) {
+                    rdatap = rdataptr_t(new AAAARdata(it->second));
+                }
+            }
+            if (rdatap == NULL) {
+                msg.set_rcode(Message::RCODE_NXDOMAIN);
+                // should add SOA to the authority section, but not implemented.
+            } else {
+                msg.set_rcode(Message::RCODE_NOERROR);
+
+                RRSet* rrset = new RRSet(query->get_name(), query->get_class(),
+                                         query->get_type(), TTL(3600));
+                rrset->add_rdata(rdatap);
+                msg.add_rrset(SECTION_ANSWER, RRSetPtr(rrset));
+            }
+
+            msg.to_wire();
+            cout << "sending a response (" <<
+                boost::lexical_cast<string>(msg.get_iobuffer().get_size())
+                 << " bytes):\n" << msg.to_text() << endl;
+            msg.get_iobuffer().send_to(s, *sa, sa_len);
+        }
+    }
+}
+
 int
 main(int argc, char* argv[])
 {
@@ -34,9 +110,17 @@
     int ch;
     const char* server_address = "127.0.0.1";
     const char* type_name = "A";
+    const char* port = "53";
+    bool receive_mode = false;
 
-    while ((ch = getopt(argc, argv, "s:t:")) != -1) {
+    while ((ch = getopt(argc, argv, "p:rs:t:")) != -1) {
         switch (ch) {
+        case 'p':
+            port = optarg;
+            break;
+        case 'r':
+            receive_mode = true;
+            break;
         case 's':
             server_address = optarg;
             break;
@@ -49,7 +133,7 @@
     argc -= optind;
     argv += optind;
 
-    if (argc < 1) {
+    if (argc < 1 && !receive_mode) {
         cerr << "usage: dnsmessage-test [-s server_address] [-t qtype] qname\n"
              << endl;
         return (1);
@@ -60,23 +144,33 @@
     memset(&hints, 0, sizeof(hints));
     hints.ai_family = AF_UNSPEC;
     hints.ai_socktype = SOCK_DGRAM;
-    e = getaddrinfo(server_address, "53", &hints, &res);
+    hints.ai_flags = receive_mode ? AI_PASSIVE : 0;
+    e = getaddrinfo(server_address, port, &hints, &res);
     if (e != 0) {
         cerr << "getaddrinfo failed: " << gai_strerror(e) << endl;
         return (1);
     }
-    
+
     int s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
     if (s < 0) {
         cerr << "failed to open socket" << endl;
         return (1);
     }
 
-    msg.set_qid(42);            // can be omitted, then QID will be 0
-    msg.set_rd(true);
-    msg.add_question(Name(argv[0]), RdataClass::IN, RdataType(type_name));
-    msg.to_wire();
-    msg.get_renderer().send_to(s, *res->ai_addr, res->ai_addrlen);
+    if (receive_mode) {
+        start_server(s, res);
+    } else {
+        msg.set_qid(42);            // can be omitted, then QID will be 0
+        msg.set_rd(true);
+        msg.add_question(Name(argv[0]), RdataClass::IN, RdataType(type_name));
+        msg.to_wire();
+        msg.get_iobuffer().send_to(s, *res->ai_addr, res->ai_addrlen);
+
+        // print sent message
+        cout << msg.to_text() << endl;
+    }
+
+    freeaddrinfo(res);
 
     return (0);
 }

Modified: experiments/jinmei-messageapi/dnsmessage.cc
==============================================================================
--- experiments/jinmei-messageapi/dnsmessage.cc (original)
+++ experiments/jinmei-messageapi/dnsmessage.cc Wed Oct  7 08:38:07 2009
@@ -15,9 +15,13 @@
 // $Id$
 
 #include <sys/types.h>
+#include <sys/socket.h>
 
 #include <stdexcept>
 
+#include <boost/lexical_cast.hpp>
+
+#include "dnsresult.hh"
 #include "rrset.hh"
 #include "dnsmessage.hh"
 
@@ -28,17 +32,21 @@
 {
     initialize();
 
-    _default_renderer = new MessageRendererToBuffer;
-    _renderer = _default_renderer;
+    _default_iobuffer = new SingleIOBuffer;
+    _iobuffer = _default_iobuffer;
 
     _default_compressor = new NameCompressor;
     _compressor = _default_compressor;
+
+    _default_decompressor = new NameDecompressor;
+    _decompressor = _default_decompressor;
 }
 
 Message::~Message()
 {
-    delete _default_renderer;
+    delete _default_iobuffer;
     delete _default_compressor;
+    delete _default_decompressor;
 }
 
 void
@@ -53,12 +61,12 @@
     }
 
     _edns = NULL;
-    _parser = NULL;
-    _renderer = NULL;
+    _iobuffer = NULL;
     _compressor = NULL;
+    _decompressor = NULL;
     _sorter = NULL;
-    _default_renderer = NULL;
     _default_compressor = NULL;
+    _default_decompressor = NULL;
 }
 
 void
@@ -83,15 +91,16 @@
 {
     uint16_t codes_and_flags;
 
-    if (_renderer == NULL)
-        throw DNSNoMessageRenderer();
+    if (_iobuffer == NULL)
+        throw DNSNoMessageIOBuffer();
 
     // reserve room for the header
-    _renderer->reserve(HEADERLEN);
+    _iobuffer->reserve(HEADERLEN);
 
     for (int section = SECTION_QUESTION; section < SECTION_MAX; ++section) {
         if (_sorter != NULL)
             _sorter->sort(*this, (section_t)section); //TBD
+        _counts[section] = 0;
         for (vector<RRSetPtr>::const_iterator it =
                  get_section((section_t)section).begin();
              it != get_section((section_t)section).end();
@@ -111,26 +120,185 @@
 
     // fill in the header
     size_t header_pos = 0;
-    _renderer->write_uint16_at(_qid, header_pos);
+    _iobuffer->write_uint16_at(_qid, header_pos);
     header_pos += sizeof(uint16_t);
     codes_and_flags = (_opcode << OPCODE_SHIFT) & OPCODE_MASK;
-    codes_and_flags |= (_rcode << RCODE_MASK);
+    codes_and_flags |= (_rcode & RCODE_MASK);
     codes_and_flags |= (_flags & FLAG_MASK);
-    _renderer->write_uint16_at(codes_and_flags, header_pos);
+    _iobuffer->write_uint16_at(codes_and_flags, header_pos);
     header_pos += sizeof(uint16_t);
     for (int section = SECTION_QUESTION; section < SECTION_MAX; ++section) {
-        _renderer->write_uint16_at(_counts[section], header_pos);
+        _iobuffer->write_uint16_at(_counts[section], header_pos);
         header_pos += sizeof(uint16_t);
     }
 }
 
-// TBD: this should be defined somewhere else.  Also, the interface should be
-// revisited.
-int
-MessageRendererToBuffer::send_to(int s, struct sockaddr& to, socklen_t to_len)
-{
-    int cc;
-
-    cc = sendto(s, &_buf[0], _buf.size(), 0, &to, to_len);
-    return (cc);
-}
+ISC::ConstResult
+Message::from_wire()
+{
+    if (_iobuffer == NULL)
+        throw DNSNoMessageIOBuffer();
+
+    if (_iobuffer->get_space() < HEADERLEN)
+        return (Result::MessageTooShort);
+
+    _qid = _iobuffer->read_uint16();
+    uint16_t codes_and_flags = _iobuffer->read_uint16();
+    _opcode = ((codes_and_flags & OPCODE_MASK) >> OPCODE_SHIFT);
+    _rcode = (codes_and_flags & RCODE_MASK);
+    _flags = (codes_and_flags & FLAG_MASK);
+    _counts[SECTION_QUESTION] = _iobuffer->read_uint16();
+    _counts[SECTION_ANSWER] = _iobuffer->read_uint16();
+    _counts[SECTION_AUTHORITY] = _iobuffer->read_uint16();
+    _counts[SECTION_ADDITIONAL] = _iobuffer->read_uint16();
+
+    ISC::ConstResult result = parse_question();
+    // parse other sections (TBD)
+
+    return (result);
+}
+
+ISC::ConstResult
+Message::parse_question()
+{
+    Name name;
+    ISC::ConstResult result;
+
+    if (_iobuffer == NULL)
+        throw DNSNoMessageIOBuffer();
+
+    for (int count = 0; count < this->_counts[SECTION_QUESTION]; count++) {
+        result = name.from_wire(get_decompressor(), *_iobuffer);
+        if (result != ISC::Result::Success)
+            goto cleanup;
+
+        // Get type and class
+        if (_iobuffer->get_space() < 2 * sizeof(uint16_t))
+            goto cleanup;
+
+        // XXX: need a duplicate check.  We might also want to have an optimized
+        // algorithm that requires the question section contain exactly one
+        // RR.
+
+        RdataType rdtype(_iobuffer->read_uint16());
+        RdataClass rdclass(_iobuffer->read_uint16());
+        add_rrset(SECTION_QUESTION,
+                  RRSetPtr(new Question(name, rdclass, rdtype))); 
+    }
+
+    return (result);
+
+  cleanup:
+    _sections[SECTION_QUESTION].clear();
+    return (result);
+}
+
+static const char *opcodetext[] = {
+    "QUERY",
+    "IQUERY",
+    "STATUS",
+    "RESERVED3",
+    "NOTIFY",
+    "UPDATE",
+    "RESERVED6",
+    "RESERVED7",
+    "RESERVED8",
+    "RESERVED9",
+    "RESERVED10",
+    "RESERVED11",
+    "RESERVED12",
+    "RESERVED13",
+    "RESERVED14",
+    "RESERVED15"
+};
+
+static const char *rcodetext[] = {
+    "NOERROR",
+    "FORMERR",
+    "SERVFAIL",
+    "NXDOMAIN",
+    "NOTIMP",
+    "REFUSED",
+    "YXDOMAIN",
+    "YXRRSET",
+    "NXRRSET",
+    "NOTAUTH",
+    "NOTZONE",
+    "RESERVED11",
+    "RESERVED12",
+    "RESERVED13",
+    "RESERVED14",
+    "RESERVED15"
+};
+
+static const char *sectiontext[] = {
+    "QUESTION",
+    "ANSWER",
+    "AUTHORITY",
+    "ADDITIONAL"
+};
+
+string
+Message::to_text() const
+{
+    string s;
+
+    s += ";; ->>HEADER<<- opcode: " + string(opcodetext[_opcode]);
+    // for simplicity we don't consider extended rcode (unlike BIND9)
+    s += ", status: " + string(rcodetext[_rcode]);
+    s += ", id: " + boost::lexical_cast<string>(_qid);
+    s += "\n;; flags: ";
+    if (get_qr())
+        s += "qr ";
+    if (get_aa())
+        s += "aa ";
+    if (get_tc())
+        s += "tc ";
+    if (get_rd())
+        s += "rd ";
+    if (get_ra())
+        s += "ra ";
+    if (get_ad())
+        s += "ad ";
+    if (get_cd())
+        s += "cd ";
+
+    // for simply, don't consider the update case
+    s += "; QUESTION: " +
+        boost::lexical_cast<string>(_counts[SECTION_QUESTION]);
+    s += ", ANSWER: " + boost::lexical_cast<string>(_counts[SECTION_ANSWER]);
+    s += ", AUTHORITY: " +
+        boost::lexical_cast<string>(_counts[SECTION_AUTHORITY]);
+    s += ", ADDITIONAL: " +
+        boost::lexical_cast<string>(_counts[SECTION_ADDITIONAL]) + "\n";
+
+    for (int section = SECTION_QUESTION; section < SECTION_MAX; ++section) {
+        if (_sections[section].empty())
+            continue;
+
+        s += "\n;; " + string(sectiontext[section]) + " SECTION:\n";
+
+        vector<RRSetPtr>::const_iterator it;
+        for (it = _sections[section].begin();
+             it !=  _sections[section].end();
+             ++it)
+        {
+            if (section == SECTION_QUESTION)
+                s += ";";
+            s += (**it).to_text() + "\n";
+        }
+    }
+
+    return (s);
+}
+
+void
+Message::make_response()
+{
+    _flags &= MESSAGE_REPLYPRESERVE;
+    set_qr(true);
+
+    for (int section = SECTION_ANSWER; section < SECTION_MAX; ++section) {
+        _sections[section].clear();
+    }
+}

Modified: experiments/jinmei-messageapi/dnsmessage.hh
==============================================================================
--- experiments/jinmei-messageapi/dnsmessage.hh (original)
+++ experiments/jinmei-messageapi/dnsmessage.hh Wed Oct  7 08:38:07 2009
@@ -25,7 +25,7 @@
 #include <boost/shared_ptr.hpp>
 
 #include "dnsexceptions.hh"
-
+#include "iobuffer.hh"
 #include "dnsname.hh"
 #include "rrset.hh"
 
@@ -40,8 +40,6 @@
 
 class Message;
 class EDNS;             // see below
-class MessageParser;
-class MessageRenderer;
 
 typedef boost::shared_ptr<AbstractRRSet> RRSetPtr;
 
@@ -51,74 +49,38 @@
 };
 
 class NameCompressor {};        // empty class for prototyping
-
-class MessageRenderer {
-public:
-    virtual void reserve(size_t len) = 0;
-    virtual void write_data(const char *cp, size_t len) = 0;
-    virtual void write_uint32(uint32_t data) = 0;
-    virtual void write_uint16(uint16_t data) = 0;
-    virtual void write_uint16_at(uint16_t data, size_t pos) = 0;
-    virtual void write_uint8(uint8_t data) = 0;
-    virtual int send_to(int s, struct sockaddr& to, socklen_t to_len) = 0;
-};
-
-class MessageRendererToBuffer : public MessageRenderer {
-public:
-    void reserve(size_t len) // XXX: API and implementation should be revisited
-    {
-        _buf.resize(len);
-    }
-    void write_data(const char *cp, size_t len)
-    { _buf.insert(_buf.end(), cp, cp + len); }
-    void write_uint32(uint32_t data)
-    {
-        data = htonl(data);
-        uint8_t* cp =  static_cast<uint8_t*>((void*)&data);
-        _buf.insert(_buf.end(), cp, cp + sizeof(uint32_t));
-    }
-    void write_uint16(uint16_t data)
-    {
-        data = htons(data);
-        uint8_t* cp =  static_cast<uint8_t*>((void*)&data);
-        _buf.insert(_buf.end(), cp, cp + sizeof(uint16_t));
-    }
-    void write_uint16_at(uint16_t data, size_t pos)
-    {
-        if (pos + sizeof(data) >= _buf.size())
-            throw DNSInvalidRendererPosition();
-
-        data = htons(data);
-        uint8_t* cp =  static_cast<uint8_t*>((void*)&data);
-        copy(cp, cp + sizeof(uint16_t), _buf.begin() + pos);
-    }
-    void write_uint8(uint8_t data)
-    {
-        _buf.push_back(data);
-    }
-    int send_to(int s, struct sockaddr& to, socklen_t to_len);
-private:
-    vector<uint8_t> _buf;
-};
+class NameDecompressor {};      // ditto
+
+#define get_msgflg(flg, capflg) \
+bool get_ ## flg() const { return ((_flags & FLAG_ ## capflg) != 0); }
+#define set_msgflg(flg, capflg) \
+bool set_ ## flg(bool on) { \
+        if (on) \
+            _flags |= FLAG_ ## capflg; \
+        else \
+            _flags &= ~FLAG_ ## capflg; \
+    }
 
 class Message {
 public:
     Message();
-    Message(MessageParser* parser);
-    Message(MessageRenderer* renderer, NameCompressor* compressor);
     ~Message();
     qid_t get_qid() const { return (_qid); }
     void set_qid(qid_t qid) { _qid = qid; }
-    bool get_rd() const { return ((_flags & FLAG_RD) != 0); }
-    void set_rd(bool on)
-    {
-        if (on)
-            _flags |= FLAG_RD;
-        else
-            _flags &= ~FLAG_RD;
-    }
-    bool get_aa() const;  // return true if set; false otherwise
-    void set_aa(bool on); // same for QR, TC, RD, RA, AD, CD
+    get_msgflg(rd, RD)
+    set_msgflg(rd, RD)
+    get_msgflg(aa, AA)
+    set_msgflg(aa, AA)
+    get_msgflg(qr, QR)
+    set_msgflg(qr, QR)
+    get_msgflg(tc, TC)
+    set_msgflg(tc, TC)
+    get_msgflg(ra, RA)
+    set_msgflg(ra, RA)
+    get_msgflg(ad, AD)
+    set_msgflg(ad, AD)
+    get_msgflg(cd, CD)
+    set_msgflg(cd, CD)
     rcode_t get_rcode() const { return (_rcode); }
     void set_rcode(rcode_t rcode) { _rcode = rcode; }
     opcode_t get_opcode() const { return (_opcode); }
@@ -152,18 +114,20 @@
     void set_edns(EDNS* edns);    // TBD
     const EDNS* get_edns() const; // TBD
 
-    // prepare for making a response from a request: see
-    // dns_message_reply() of BIND9
-    void make_response(MessageRenderer* renderer, NameCompressor* compressor);
+    // prepare for making a response from a request.  This will clear the
+    // DNS header except those fields that should be kept for the response,
+    // and clear answer and the following sections.
+    // see also dns_message_reply() of BIND9.
+    void make_response();
 
     // Render message
     void to_wire();      // should probably return some result code?
 
-    MessageRenderer& get_renderer()
+    IOBuffer& get_iobuffer()
     {
-        if (_renderer == NULL)
-            throw DNSNoMessageRenderer();
-        return (*_renderer);
+        if (_iobuffer == NULL)
+            throw DNSNoMessageIOBuffer();
+        return (*_iobuffer);
     }
 
     NameCompressor& get_compressor()
@@ -173,11 +137,38 @@
         return (*_compressor);
     }
 
-    // Parse message: TBD
-    void parse();
+    NameDecompressor& get_decompressor()
+    {
+        if (_decompressor == NULL)
+            throw DNSNoNameDecompressor();
+        return (*_decompressor);
+    }
+
+    // Parse message:
+    // In general, we don't trust data from wire, so we return an explicit
+    // error code rather than throw an exception when we encounter a malformed
+    // message.  We cannot make it a constructor for the same reason.
+    ISC::ConstResult from_wire();
+
+public:
+    // public protocol constants
+    static const rcode_t RCODE_NOERROR = 0;
+    static const rcode_t RCODE_FORMERR = 1;
+    static const rcode_t RCODE_SERVFAIL = 2;
+    static const rcode_t RCODE_NXDOMAIN = 3;
+    static const rcode_t RCODE_NOTIMP = 4;
+    static const rcode_t RCODE_REFUSED = 5;
+    // ...more to follow
+
+    static const opcode_t OPCODE_QUERY = 0;
+    static const opcode_t OPCODE_IQUERY = 1;
+    static const opcode_t OPCODE_STATUS = 2;
+    static const opcode_t OPCODE_NOTIFY = 4;
+    static const opcode_t OPCODE_UPDATE = 5;
 
 private:
     void initialize();
+    ISC::ConstResult parse_question();
 
 private:
     // Open issues: should we rather have a header in wire-format
@@ -194,31 +185,18 @@
 
     // tsig/sig0: TODO
     EDNS* _edns;
-    MessageParser* _parser;
-    MessageRenderer* _renderer;
+    IOBuffer* _iobuffer;
     NameCompressor* _compressor;
+    NameDecompressor* _decompressor;
     RRSetsSorter* _sorter;
 
     // created internally with the default constructor.  TBD: revisit this idea.
-    MessageRenderer* _default_renderer;
+    IOBuffer* _default_iobuffer;
     NameCompressor* _default_compressor;
+    NameDecompressor* _default_decompressor;
 
     // protocol constants
     static const size_t HEADERLEN = 12;
-
-    static const rcode_t RCODE_NOERROR = 0;
-    static const rcode_t RCODE_FORMERR = 1;
-    static const rcode_t RCODE_SERVFAIL = 2;
-    static const rcode_t RCODE_NXDOMAIN = 3;
-    static const rcode_t RCODE_NOTIMP = 4;
-    static const rcode_t RCODE_REFUSED = 5;
-    // ...more to follow
-
-    static const opcode_t OPCODE_QUERY = 0;
-    static const opcode_t OPCODE_IQUERY = 1;
-    static const opcode_t OPCODE_STATUS = 2;
-    static const opcode_t OPCODE_NOTIFY = 4;
-    static const opcode_t OPCODE_UPDATE = 5;
 
     static const flags_t FLAG_QR = 0x8000;
     static const flags_t FLAG_AA = 0x0400;
@@ -232,6 +210,8 @@
     static const unsigned int OPCODE_SHIFT = 11;
     static const unsigned int RCODE_MASK = 0x000f;
     static const unsigned int FLAG_MASK = 0x8ff0;
+
+    static const unsigned int MESSAGE_REPLYPRESERVE = (FLAG_RD | FLAG_CD);
 };
 }
 }

Modified: experiments/jinmei-messageapi/dnsname.cc
==============================================================================
--- experiments/jinmei-messageapi/dnsname.cc (original)
+++ experiments/jinmei-messageapi/dnsname.cc Wed Oct  7 08:38:07 2009
@@ -16,6 +16,8 @@
 
 #include <stdexcept>
 
+#include "dnsresult.hh"
+#include "iobuffer.hh"
 #include "dnsname.hh"
 #include "dnsmessage.hh"
 #include "dnsexceptions.hh"
@@ -32,6 +34,13 @@
     ft_escdecimal,
     ft_at
 } ft_state;
+
+typedef enum {
+    fw_start = 0,
+    fw_ordinary,
+    fw_copy,
+    fw_newcurrent
+} fw_state;
 
 static char digitvalue[256] = {
     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 16
@@ -400,11 +409,115 @@
 }
 
 void
-Name::to_wire(MessageRenderer& r, NameCompressor& c) const
+Name::to_wire(IOBuffer& b, 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
+    b.write_data(_ndata.c_str(), _ndata.size());
+    if (!_is_absolute)     // should be revisited
+        b.write_uint8(0);           // XXX: explicitly need trailing null char
+}
+
+const ISC::Result*
+Name::from_wire(NameDecompressor& decompressor, IOBuffer& source)
+{
+    unsigned int nused, labels, n, nmax;
+    unsigned int current;
+    bool done;
+    fw_state state = fw_start;
+    unsigned int c;
+    bool downcase;
+    bool seen_pointer;
+
+    /*
+     * Initialize things to make the compiler happy; they're not required.
+     */
+    n = 0;
+
+    /*
+     * Set up.
+     */
+    labels = 0;
+    done = false;
+    nused = 0;
+
+    /*
+     * Find the maximum number of uncompressed target name
+     * bytes we are willing to generate.  This is the smaller
+     * of the available target buffer length and the
+     * maximum legal domain name length (255).
+     */
+    nmax = NAME_MAXWIRE;
+
+    current = source.get_current();
+
+    /*
+     * Note:  The following code is not optimized for speed, but
+     * rather for correctness.  Speed will be addressed in the future.
+     */
+    while (current < source.get_size() && !done) {
+        c = source.read_uint8();
+        current++;
+
+        switch (state) {
+        case fw_start:
+            if (c < 64) {
+                _offsets.push_back(nused);
+                labels++;
+                if (nused + c + 1 > nmax)
+                    goto full;
+                nused += c + 1;
+                _ndata.push_back(c);
+                if (c == 0)
+                    done = true;
+                n = c;
+                state = fw_ordinary;
+            } else if (c >= 128 && c < 192) {
+                /*
+                 * 14 bit local compression pointer.
+                 * Local compression is no longer an
+                 * IETF draft.
+                 */
+                return (ISC::DNS::Result::BadLabelType);
+            } else if (c >= 192) {
+                /*
+                 * Ordinary 14-bit pointer.
+                 */
+                return (ISC::DNS::Result::BadLabelType); // XXX not implemented
+            } else
+                return (ISC::DNS::Result::BadLabelType);
+            break;
+        case fw_ordinary:
+            if (downcase)
+                c = maptolower[c];
+            /* FALLTHROUGH */
+        case fw_copy:
+            _ndata.push_back(c);
+            n--;
+            if (n == 0)
+                state = fw_start;
+            break;
+        case fw_newcurrent:
+            // XXX not implemented, fall through
+        default:
+            throw ISCUnexpected();
+        }
+    }
+
+    if (!done)
+        return (ISC::Result::Unexpected);
+
+    _labels = labels;
+    _length = nused;
+    _is_absolute = true;
+
+    return (ISC::Result::Success);
+
+  full:
+    /*
+     * The name did not fit even though we had a buffer
+     * big enough to fit a maximum-length name.
+     */
+    return (ISC::DNS::Result::NameTooLong);
 }
 
 bool

Modified: experiments/jinmei-messageapi/dnsname.hh
==============================================================================
--- experiments/jinmei-messageapi/dnsname.hh (original)
+++ experiments/jinmei-messageapi/dnsname.hh Wed Oct  7 08:38:07 2009
@@ -22,13 +22,15 @@
 
 #include "iscexceptions.hh"
 #include "dnsexceptions.hh"
+#include "dnsresult.hh"
+#include "iobuffer.hh"
 
 using namespace std;
 
 namespace ISC {
 namespace DNS {
-class MessageRenderer;
 class NameCompressor;
+class NameDecompressor;
 
 typedef enum {
     namereln_none = 0,
@@ -67,7 +69,8 @@
 
     // public methods
     string to_text(bool omit_final_dot) const;
-    void to_wire(MessageRenderer& r, NameCompressor& c) const;
+    void to_wire(IOBuffer& r, NameCompressor& c) const;
+    const ISC::Result* from_wire(NameDecompressor& c, IOBuffer& iobuf);
     unsigned int countlabels() const { return (_labels); }
     NameComparisonResult fullcompare(const Name &other) const;
     Name split(unsigned int first, unsigned int n) const;
@@ -83,6 +86,8 @@
     bool operator>=(const Name &other) const;
     bool operator<(const Name &other) const;
     bool operator>(const Name &other) const;
+
+    static const unsigned int NAME_MAXWIRE = 255;
 private:
     string _ndata; // or vector<unsigned char>?
     vector<char> _offsets;

Modified: experiments/jinmei-messageapi/iscexceptions.hh
==============================================================================
--- experiments/jinmei-messageapi/iscexceptions.hh (original)
+++ experiments/jinmei-messageapi/iscexceptions.hh Wed Oct  7 08:38:07 2009
@@ -20,7 +20,9 @@
 namespace ISC {
 // quick hack exception classes
 class ISCException {};
+class ISCUnexpected : public ISCException {};
 class ISCNoSpace : public ISCException {};
 class ISCInvalidAddressString : public ISCException {};
+class ISCIOBufferInvalidPosition : public ISCException {};
 }
 #endif  // __ISCEXCEPTIONS_HH

Modified: experiments/jinmei-messageapi/rrset.cc
==============================================================================
--- experiments/jinmei-messageapi/rrset.cc (original)
+++ experiments/jinmei-messageapi/rrset.cc Wed Oct  7 08:38:07 2009
@@ -52,9 +52,9 @@
 }
 
 void
-RdataClass::to_wire(MessageRenderer& r) const
-{
-    r.write_uint16(_classval);
+RdataClass::to_wire(IOBuffer& b) const
+{
+    b.write_uint16(_classval);
 }
 
 const RdataClass RdataClass::IN("IN");
@@ -83,9 +83,9 @@
 }
 
 void
-RdataType::to_wire(MessageRenderer& r) const
-{
-    r.write_uint16(_typeval);
+RdataType::to_wire(IOBuffer& b) const
+{
+    b.write_uint16(_typeval);
 }
 
 const RdataType RdataType::A("A");
@@ -93,9 +93,9 @@
 // ...more to follow
 
 void
-TTL::to_wire(MessageRenderer& r) const
-{
-    r.write_uint16(_ttlval);
+TTL::to_wire(IOBuffer& b) const
+{
+    b.write_uint32(_ttlval);
 }
 
 ARdata::ARdata(const string& addrstr)
@@ -113,9 +113,10 @@
 }
 
 void
-ARdata::to_wire(MessageRenderer& renderer, NameCompressor& compressor) const
-{
-    //TBD: copy (const char *)&_addr, sizeof(_addr)
+ARdata::to_wire(IOBuffer& buffer, NameCompressor& compressor) const
+{
+    buffer.write_uint16(sizeof(_addr));
+    buffer.write_data(static_cast<const char *>((void *)&_addr), sizeof(_addr));
 }
 
 string
@@ -144,9 +145,10 @@
 }
 
 void
-AAAARdata::to_wire(MessageRenderer& renderer, NameCompressor& compressor) const
-{
-    //TBD: copy (const char *)&_addr, sizeof(_addr)
+AAAARdata::to_wire(IOBuffer& buffer, NameCompressor& compressor) const
+{
+    buffer.write_uint16(sizeof(_addr));
+    buffer.write_data(static_cast<const char *>((void *)&_addr), sizeof(_addr));
 }
 
 string
@@ -221,17 +223,17 @@
     // sort Rdata list based on rrset-order and sortlist, and possible
     // other options.  Details to be considered.
 
-    MessageRenderer& r = message.get_renderer();
+    IOBuffer& b = message.get_iobuffer();
     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);
+        _name.to_wire(b, c);
+        _rdtype.to_wire(b);
+        _rdclass.to_wire(b);
+        _ttl.to_wire(b);
+        (**it).to_wire(b, c);
 
         // TBD: handle truncation case
     }
@@ -251,12 +253,12 @@
 int
 Question::to_wire(Message& message, section_t section)
 {
-    MessageRenderer& r = message.get_renderer();
+    IOBuffer& b = message.get_iobuffer();
     NameCompressor& c = message.get_compressor();
 
-    _name.to_wire(r, c);
-    _rdtype.to_wire(r);
-    _rdclass.to_wire(r);
+    _name.to_wire(b, c);
+    _rdtype.to_wire(b);
+    _rdclass.to_wire(b);
 
     return (1);
 }
@@ -268,7 +270,7 @@
     // 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();
+    IOBuffer& b = message.get_iobuffer();
 
     // directly copy or link to wire-formatted data in the renderer for
     // faster rendering.  details to be considered.

Modified: experiments/jinmei-messageapi/rrset.hh
==============================================================================
--- experiments/jinmei-messageapi/rrset.hh (original)
+++ experiments/jinmei-messageapi/rrset.hh Wed Oct  7 08:38:07 2009
@@ -42,7 +42,6 @@
 // to care much more about resource leak.
 //typedef Rdata * rdataptr_t;
 class Message;
-class MessageRenderer;
 class NameCompressor;
 
 // XXX: this should be defined somewhere else.
@@ -59,7 +58,7 @@
         _classval(classval) {}
     explicit RdataClass(const string& classstr);
     const string to_text() const;
-    void to_wire(MessageRenderer& r) const;
+    void to_wire(IOBuffer& b) const;
     uint16_t get_value() const { return (_classval); }
     bool operator==(const RdataClass& other) const
     { return (_classval == other._classval); }
@@ -80,7 +79,7 @@
         _typeval(typeval) {}
     explicit RdataType(const string& typestr);
     const string to_text() const;
-    void to_wire(MessageRenderer& r) const;
+    void to_wire(IOBuffer& b) const;
     uint16_t get_value() const { return (_typeval); }
     bool operator==(const RdataType& other) const
     { return (_typeval == other._typeval); }
@@ -105,7 +104,7 @@
     TTL(uint32_t ttlval) : _ttlval(ttlval) {}
     string to_text() const
     { return (boost::lexical_cast<string>(_ttlval)); }
-    void to_wire(MessageRenderer& r) const;
+    void to_wire(IOBuffer& b) const;
     uint32_t get_value() { return (_ttlval); }
     bool operator==(const TTL& other) const
     { return (_ttlval == other._ttlval); }
@@ -128,8 +127,7 @@
     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;
+    virtual void to_wire(IOBuffer& b, NameCompressor& c) const = 0;
     // need generic method for getting n-th field? c.f. ldns
     // e.g. string getField(int n);
 };
@@ -165,7 +163,7 @@
     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;
+    void to_wire(IOBuffer& b, NameCompressor& c) const;
     const struct in_addr& getAddress() const
     { return (_addr); }
     bool operator==(const ARdata &other) const
@@ -189,7 +187,7 @@
     static const RdataType& get_type_static()
     { return (RdataType::AAAA); }
     void from_wire(const string& wireData);
-    void to_wire(MessageRenderer& r, NameCompressor& c) const;
+    void to_wire(IOBuffer& b, NameCompressor& c) const;
     const struct in6_addr& getAddress() const
     { return (_addr); }
     bool operator==(const AAAARdata &other) const
@@ -322,7 +320,7 @@
     explicit RR(const string& rrstr);
     explicit RR(const Name &name, const RdataClass &rdclass,
                 const RdataType &rdtype, const TTL &ttl,
-                const Rdata &rdata) {}
+                const Rdata &rdata);
     string to_text() const
     { return (_rrset.to_text()); }
     const Name& get_name() const




More information about the bind10-changes mailing list