[svn] commit: r3108 - in /branches/trac327/src: bin/auth/ bin/auth/tests/ bin/bind10/ bin/recurse/ bin/recurse/tests/ lib/asiolink/ lib/asiolink/internal/ lib/dns/

BIND 10 source code commits bind10-changes at lists.isc.org
Sun Oct 3 06:44:40 UTC 2010


Author: each
Date: Sun Oct  3 06:44:36 2010
New Revision: 3108

Log:
b10-recurse can now act as a simple forwarder.  To switch this on,
use the "-f nameserver" option to the bind10 boss script (eventually
that will have to be a config system option).  This can currently only
send upstream queries via UDP, without any niceties like EDNS0, DNSSEC,
checking for QID match, etc.  Also, still very poorly documented.  More
to come...

Modified:
    branches/trac327/src/bin/auth/auth_srv.cc
    branches/trac327/src/bin/auth/auth_srv.h
    branches/trac327/src/bin/auth/tests/auth_srv_unittest.cc
    branches/trac327/src/bin/bind10/bind10.py.in
    branches/trac327/src/bin/bind10/run_bind10.sh.in
    branches/trac327/src/bin/recurse/main.cc
    branches/trac327/src/bin/recurse/recursor.cc
    branches/trac327/src/bin/recurse/recursor.h
    branches/trac327/src/bin/recurse/tests/recursor_unittest.cc
    branches/trac327/src/lib/asiolink/asiolink.cc
    branches/trac327/src/lib/asiolink/asiolink.h
    branches/trac327/src/lib/asiolink/internal/tcpdns.h
    branches/trac327/src/lib/asiolink/internal/udpdns.h
    branches/trac327/src/lib/asiolink/tcpdns.cc
    branches/trac327/src/lib/asiolink/udpdns.cc
    branches/trac327/src/lib/dns/buffer.h
    branches/trac327/src/lib/dns/message.h
    branches/trac327/src/lib/dns/messagerenderer.h

Modified: branches/trac327/src/bin/auth/auth_srv.cc
==============================================================================
--- branches/trac327/src/bin/auth/auth_srv.cc (original)
+++ branches/trac327/src/bin/auth/auth_srv.cc Sun Oct  3 06:44:36 2010
@@ -72,12 +72,12 @@
     ~AuthSrvImpl();
     isc::data::ConstElementPtr setDbFile(isc::data::ConstElementPtr config);
 
-    bool processNormalQuery(const IOMessage& io_message, Message& message,
-                            MessageRenderer& response_renderer);
-    bool processAxfrQuery(const IOMessage& io_message, Message& message,
-                            MessageRenderer& response_renderer);
-    bool processNotify(const IOMessage& io_message, Message& message, 
-                            MessageRenderer& response_renderer);
+    bool processNormalQuery(const IOMessage& io_message, MessagePtr message,
+                            OutputBufferPtr buffer);
+    bool processAxfrQuery(const IOMessage& io_message, MessagePtr message,
+                          OutputBufferPtr buffer);
+    bool processNotify(const IOMessage& io_message, MessagePtr message, 
+                       OutputBufferPtr buffer);
     std::string db_file_;
     ModuleCCSession* config_session_;
     MetaDataSrc data_sources_;
@@ -131,13 +131,10 @@
 class MessageLookup : public DNSLookup {
 public:
     MessageLookup(AuthSrv* srv) : server_(srv) {}
-    virtual void operator()(const IOMessage& io_message,
-                            isc::dns::Message& dns_message,
-                            isc::dns::MessageRenderer& renderer,
-                            BasicServer* server, bool& complete) const
+    virtual void operator()(const IOMessage& io_message, MessagePtr message,
+                            OutputBufferPtr buffer, IOServer* server) const
     {
-        server_->processMessage(io_message, dns_message, renderer,
-                                server, complete);
+        server_->processMessage(io_message, message, buffer, server);
     }
 private:
     AuthSrv* server_;
@@ -150,19 +147,19 @@
 class MessageAnswer : public DNSAnswer {
 public:
     MessageAnswer(AuthSrv* srv) : server_(srv) {}
-    virtual void operator()(const IOMessage& io_message,
-                            isc::dns::Message& message,
-                            isc::dns::MessageRenderer& renderer) const
+    virtual void operator()(const IOMessage& io_message, MessagePtr message,
+                            OutputBufferPtr buffer) const
     {
+        MessageRenderer renderer(*buffer);
         if (io_message.getSocket().getProtocol() == IPPROTO_UDP) {
-            renderer.setLengthLimit(message.getUDPSize());
+            renderer.setLengthLimit(message->getUDPSize());
         } else {
             renderer.setLengthLimit(65535);
         }
-        message.toWire(renderer);
+        message->toWire(renderer);
         if (server_->getVerbose()) {
             cerr << "[b10-recurse] sending a response (" << renderer.getLength()
-                 << " bytes):\n" << message.toText() << endl;
+                 << " bytes):\n" << message->toText() << endl;
         }
     }
 
@@ -202,50 +199,52 @@
 namespace {
 class QuestionInserter {
 public:
-    QuestionInserter(Message* message) : message_(message) {}
+    QuestionInserter(MessagePtr message) : message_(message) {}
     void operator()(const QuestionPtr question) {
         message_->addQuestion(question);
     }
-    Message* message_;
+    MessagePtr message_;
 };
 
 void
-makeErrorMessage(Message& message, MessageRenderer& renderer,
+makeErrorMessage(MessagePtr message, OutputBufferPtr buffer,
                  const Rcode& rcode, const bool verbose_mode)
 {
     // extract the parameters that should be kept.
     // XXX: with the current implementation, it's not easy to set EDNS0
     // depending on whether the query had it.  So we'll simply omit it.
-    const qid_t qid = message.getQid();
-    const bool rd = message.getHeaderFlag(MessageFlag::RD());
-    const bool cd = message.getHeaderFlag(MessageFlag::CD());
-    const Opcode& opcode = message.getOpcode();
+    const qid_t qid = message->getQid();
+    const bool rd = message->getHeaderFlag(MessageFlag::RD());
+    const bool cd = message->getHeaderFlag(MessageFlag::CD());
+    const Opcode& opcode = message->getOpcode();
     vector<QuestionPtr> questions;
 
     // If this is an error to a query or notify, we should also copy the
     // question section.
     if (opcode == Opcode::QUERY() || opcode == Opcode::NOTIFY()) {
-        questions.assign(message.beginQuestion(), message.endQuestion());
-    }
-
-    message.clear(Message::RENDER);
-    message.setQid(qid);
-    message.setOpcode(opcode);
-    message.setHeaderFlag(MessageFlag::QR());
-    message.setUDPSize(AuthSrvImpl::DEFAULT_LOCAL_UDPSIZE);
+        questions.assign(message->beginQuestion(), message->endQuestion());
+    }
+
+    message->clear(Message::RENDER);
+    message->setQid(qid);
+    message->setOpcode(opcode);
+    message->setHeaderFlag(MessageFlag::QR());
+    message->setUDPSize(AuthSrvImpl::DEFAULT_LOCAL_UDPSIZE);
     if (rd) {
-        message.setHeaderFlag(MessageFlag::RD());
+        message->setHeaderFlag(MessageFlag::RD());
     }
     if (cd) {
-        message.setHeaderFlag(MessageFlag::CD());
-    }
-    for_each(questions.begin(), questions.end(), QuestionInserter(&message));
-    message.setRcode(rcode);
-    message.toWire(renderer);
+        message->setHeaderFlag(MessageFlag::CD());
+    }
+    for_each(questions.begin(), questions.end(), QuestionInserter(message));
+    message->setRcode(rcode);
+
+    MessageRenderer renderer(*buffer);
+    message->toWire(renderer);
 
     if (verbose_mode) {
         cerr << "[b10-auth] sending an error response (" <<
-            renderer.getLength() << " bytes):\n" << message.toText() << endl;
+            renderer.getLength() << " bytes):\n" << message->toText() << endl;
     }
 }
 }
@@ -276,148 +275,139 @@
 }
 
 void
-AuthSrv::processMessage(const IOMessage& io_message, Message& message,
-                        MessageRenderer& response_renderer,
-                        BasicServer* server, bool& complete)
+AuthSrv::processMessage(const IOMessage& io_message, MessagePtr message,
+                        OutputBufferPtr buffer, IOServer* server)
 {
     InputBuffer request_buffer(io_message.getData(), io_message.getDataSize());
 
     // First, check the header part.  If we fail even for the base header,
     // just drop the message.
     try {
-        message.parseHeader(request_buffer);
+        message->parseHeader(request_buffer);
 
         // Ignore all responses.
-        if (message.getHeaderFlag(MessageFlag::QR())) {
+        if (message->getHeaderFlag(MessageFlag::QR())) {
             if (impl_->verbose_mode_) {
                 cerr << "[b10-auth] received unexpected response, ignoring"
                      << endl;
             }
-            complete = false;
-            server->resume();
+            server->resume(false);
             return;
         }
     } catch (const Exception& ex) {
         if (impl_->verbose_mode_) {
             cerr << "[b10-auth] DNS packet exception: " << ex.what() << endl;
         }
-        complete = false;
-        server->resume();
+        server->resume(false);
         return;
     }
 
     try {
         // Parse the message.
-        message.fromWire(request_buffer);
+        message->fromWire(request_buffer);
     } catch (const DNSProtocolError& error) {
         if (impl_->verbose_mode_) {
             cerr << "[b10-auth] returning " <<  error.getRcode().toText()
                  << ": " << error.what() << endl;
         }
-        makeErrorMessage(message, response_renderer, error.getRcode(),
+        makeErrorMessage(message, buffer, error.getRcode(),
                          impl_->verbose_mode_);
-        complete = true;
-        server->resume();
+        server->resume(true);
         return;
     } catch (const Exception& ex) {
         if (impl_->verbose_mode_) {
             cerr << "[b10-auth] returning SERVFAIL: " << ex.what() << endl;
         }
-        makeErrorMessage(message, response_renderer, Rcode::SERVFAIL(),
+        makeErrorMessage(message, buffer, Rcode::SERVFAIL(),
                          impl_->verbose_mode_);
-        complete = true;
-        server->resume();
+        server->resume(true);
         return;
     } // other exceptions will be handled at a higher layer.
 
     if (impl_->verbose_mode_) {
-        cerr << "[b10-auth] received a message:\n" << message.toText() << endl;
+        cerr << "[b10-auth] received a message:\n" << message->toText() << endl;
     }
 
     // Perform further protocol-level validation.
 
-    if (message.getOpcode() == Opcode::NOTIFY()) {
-        complete = impl_->processNotify(io_message, message,
-                                         response_renderer);
-    } else if (message.getOpcode() != Opcode::QUERY()) {
+    bool sendAnswer = true;
+    if (message->getOpcode() == Opcode::NOTIFY()) {
+        sendAnswer = impl_->processNotify(io_message, message, buffer);
+    } else if (message->getOpcode() != Opcode::QUERY()) {
         if (impl_->verbose_mode_) {
             cerr << "[b10-auth] unsupported opcode" << endl;
         }
-        makeErrorMessage(message, response_renderer, Rcode::NOTIMP(),
+        makeErrorMessage(message, buffer, Rcode::NOTIMP(),
                          impl_->verbose_mode_);
-        complete = true;
-    } else if (message.getRRCount(Section::QUESTION()) != 1) {
-        makeErrorMessage(message, response_renderer, Rcode::FORMERR(),
+    } else if (message->getRRCount(Section::QUESTION()) != 1) {
+        makeErrorMessage(message, buffer, Rcode::FORMERR(),
                          impl_->verbose_mode_);
-        complete = true;
     } else {
-        ConstQuestionPtr question = *message.beginQuestion();
+        ConstQuestionPtr question = *message->beginQuestion();
         const RRType &qtype = question->getType();
         if (qtype == RRType::AXFR()) {
-            complete = impl_->processAxfrQuery(io_message, message,
-                                                response_renderer);
+            sendAnswer = impl_->processAxfrQuery(io_message, message, buffer);
         } else if (qtype == RRType::IXFR()) {
-            makeErrorMessage(message, response_renderer, Rcode::NOTIMP(),
-                         impl_->verbose_mode_);
-            complete = true;
+            makeErrorMessage(message, buffer, Rcode::NOTIMP(),
+                             impl_->verbose_mode_);
         } else {
-            complete = impl_->processNormalQuery(io_message, message,
-                                               response_renderer);
-        }
-    }
-
-    server->resume();
+            sendAnswer = impl_->processNormalQuery(io_message, message, buffer);
+        }
+    }
+
+    server->resume(sendAnswer);
 }
 
 bool
-AuthSrvImpl::processNormalQuery(const IOMessage& io_message, Message& message,
-                                MessageRenderer& response_renderer)
+AuthSrvImpl::processNormalQuery(const IOMessage& io_message, MessagePtr message,
+                                OutputBufferPtr buffer)
 {
-    const bool dnssec_ok = message.isDNSSECSupported();
-    const uint16_t remote_bufsize = message.getUDPSize();
-
-    message.makeResponse();
-    message.setHeaderFlag(MessageFlag::AA());
-    message.setRcode(Rcode::NOERROR());
-    message.setDNSSECSupported(dnssec_ok);
-    message.setUDPSize(AuthSrvImpl::DEFAULT_LOCAL_UDPSIZE);
+    const bool dnssec_ok = message->isDNSSECSupported();
+    const uint16_t remote_bufsize = message->getUDPSize();
+
+    message->makeResponse();
+    message->setHeaderFlag(MessageFlag::AA());
+    message->setRcode(Rcode::NOERROR());
+    message->setDNSSECSupported(dnssec_ok);
+    message->setUDPSize(AuthSrvImpl::DEFAULT_LOCAL_UDPSIZE);
 
     try {
-        Query query(message, cache_, dnssec_ok);
+        Query query(*message, cache_, dnssec_ok);
         data_sources_.doQuery(query);
     } catch (const Exception& ex) {
         if (verbose_mode_) {
             cerr << "[b10-auth] Internal error, returning SERVFAIL: " <<
                 ex.what() << endl;
         }
-        makeErrorMessage(message, response_renderer, Rcode::SERVFAIL(),
-                         verbose_mode_);
+        makeErrorMessage(message, buffer, Rcode::SERVFAIL(), verbose_mode_);
         return (true);
     }
 
+
+    MessageRenderer renderer(*buffer);
     const bool udp_buffer =
         (io_message.getSocket().getProtocol() == IPPROTO_UDP);
-    response_renderer.setLengthLimit(udp_buffer ? remote_bufsize : 65535);
-    message.toWire(response_renderer);
+    renderer.setLengthLimit(udp_buffer ? remote_bufsize : 65535);
+    message->toWire(renderer);
+
     if (verbose_mode_) {
         cerr << "[b10-auth] sending a response ("
-             << response_renderer.getLength()
-             << " bytes):\n" << message.toText() << endl;
+             << renderer.getLength()
+             << " bytes):\n" << message->toText() << endl;
     }
 
     return (true);
 }
 
 bool
-AuthSrvImpl::processAxfrQuery(const IOMessage& io_message, Message& message,
-                            MessageRenderer& response_renderer)
+AuthSrvImpl::processAxfrQuery(const IOMessage& io_message, MessagePtr message,
+                              OutputBufferPtr buffer)
 {
     if (io_message.getSocket().getProtocol() == IPPROTO_UDP) {
         if (verbose_mode_) {
             cerr << "[b10-auth] AXFR query over UDP isn't allowed" << endl;
         }
-        makeErrorMessage(message, response_renderer, Rcode::FORMERR(),
-                         verbose_mode_);
+        makeErrorMessage(message, buffer, Rcode::FORMERR(), verbose_mode_);
         return (true);
     }
 
@@ -442,8 +432,7 @@
             cerr << "[b10-auth] Error in handling XFR request: " << err.what()
                  << endl;
         }
-        makeErrorMessage(message, response_renderer, Rcode::SERVFAIL(),
-                         verbose_mode_);
+        makeErrorMessage(message, buffer, Rcode::SERVFAIL(), verbose_mode_);
         return (true);
     }
 
@@ -454,28 +443,26 @@
 }
 
 bool
-AuthSrvImpl::processNotify(const IOMessage& io_message, Message& message, 
-                           MessageRenderer& response_renderer) 
+AuthSrvImpl::processNotify(const IOMessage& io_message, MessagePtr message, 
+                           OutputBufferPtr buffer)
 {
     // The incoming notify must contain exactly one question for SOA of the
     // zone name.
-    if (message.getRRCount(Section::QUESTION()) != 1) {
+    if (message->getRRCount(Section::QUESTION()) != 1) {
         if (verbose_mode_) {
                 cerr << "[b10-auth] invalid number of questions in notify: "
-                     << message.getRRCount(Section::QUESTION()) << endl;
-        }
-        makeErrorMessage(message, response_renderer, Rcode::FORMERR(),
-                         verbose_mode_);
+                     << message->getRRCount(Section::QUESTION()) << endl;
+        }
+        makeErrorMessage(message, buffer, Rcode::FORMERR(), verbose_mode_);
         return (true);
     }
-    ConstQuestionPtr question = *message.beginQuestion();
+    ConstQuestionPtr question = *message->beginQuestion();
     if (question->getType() != RRType::SOA()) {
         if (verbose_mode_) {
                 cerr << "[b10-auth] invalid question RR type in notify: "
                      << question->getType() << endl;
         }
-        makeErrorMessage(message, response_renderer, Rcode::FORMERR(),
-                         verbose_mode_);
+        makeErrorMessage(message, buffer, Rcode::FORMERR(), verbose_mode_);
         return (true);
     }
 
@@ -533,10 +520,12 @@
         return (false);
     }
 
-    message.makeResponse();
-    message.setHeaderFlag(MessageFlag::AA());
-    message.setRcode(Rcode::NOERROR());
-    message.toWire(response_renderer);
+    message->makeResponse();
+    message->setHeaderFlag(MessageFlag::AA());
+    message->setRcode(Rcode::NOERROR());
+
+    MessageRenderer renderer(*buffer);
+    message->toWire(renderer);
     return (true);
 }
 

Modified: branches/trac327/src/bin/auth/auth_srv.h
==============================================================================
--- branches/trac327/src/bin/auth/auth_srv.h (original)
+++ branches/trac327/src/bin/auth/auth_srv.h Sun Oct  3 06:44:36 2010
@@ -25,12 +25,6 @@
 #include <asiolink/asiolink.h>
 
 namespace isc {
-namespace dns {
-class InputBuffer;
-class Message;
-class MessageRenderer;
-}
-
 namespace xfr {
 class AbstractXfroutClient;
 }
@@ -67,9 +61,9 @@
     /// \return \c true if the \message contains a response to be returned;
     /// otherwise \c false.
     void processMessage(const asiolink::IOMessage& io_message,
-                        isc::dns::Message& message,
-                        isc::dns::MessageRenderer& response_renderer,
-                        asiolink::BasicServer* server, bool& complete);
+                        isc::dns::MessagePtr message,
+                        isc::dns::OutputBufferPtr buffer,
+                        asiolink::IOServer* server);
     void setVerbose(bool on);
     bool getVerbose() const;
     isc::data::ConstElementPtr updateConfig(isc::data::ConstElementPtr config);

Modified: branches/trac327/src/bin/auth/tests/auth_srv_unittest.cc
==============================================================================
--- branches/trac327/src/bin/auth/tests/auth_srv_unittest.cc (original)
+++ branches/trac327/src/bin/auth/tests/auth_srv_unittest.cc Sun Oct  3 06:44:36 2010
@@ -123,21 +123,29 @@
     };
 
     // A nonoperative task object to be used in calls to processMessage()
-    class MockTask : public BasicServer {
+    class MockTask : public IOServer {
+    public:
+        MockTask() : done_(false) {}
         void operator()(asio::error_code ec UNUSED_PARAM,
                         size_t length UNUSED_PARAM)
         {}
+        // virtual void doLookup() { return; }
+        virtual void resume(const bool done) { done_ = done; }
+        virtual bool hasAnswer() { return (done_); }
+        virtual int value() { return (0); }
+    private:
+        bool done_;
     };
 
 protected:
     AuthSrvTest() : server(true, xfrout),
                     request_message(Message::RENDER),
-                    parse_message(Message::PARSE), default_qid(0x1035),
-                    opcode(Opcode(Opcode::QUERY())), qname("www.example.com"),
-                    qclass(RRClass::IN()), qtype(RRType::A()),
-                    io_message(NULL), endpoint(NULL), request_obuffer(0),
-                    request_renderer(request_obuffer),
-                    response_obuffer(0), response_renderer(response_obuffer)
+                    parse_message(new Message(Message::PARSE)),
+                    default_qid(0x1035), opcode(Opcode(Opcode::QUERY())),
+                    qname("www.example.com"), qclass(RRClass::IN()),
+                    qtype(RRType::A()), io_message(NULL), endpoint(NULL),
+                    request_obuffer(0), request_renderer(request_obuffer),
+                    response_obuffer(new OutputBuffer(0))
     {
         server.setXfrinSession(&notify_session);
     }
@@ -147,10 +155,10 @@
     }
     MockSession notify_session;
     MockXfroutClient xfrout;
-    MockTask noOp;
+    MockTask task;
     AuthSrv server;
     Message request_message;
-    Message parse_message;
+    MessagePtr parse_message;
     const qid_t default_qid;
     const Opcode opcode;
     const Name qname;
@@ -161,8 +169,7 @@
     const IOEndpoint* endpoint;
     OutputBuffer request_obuffer;
     MessageRenderer request_renderer;
-    OutputBuffer response_obuffer;
-    MessageRenderer response_renderer;
+    OutputBufferPtr response_obuffer;
     vector<uint8_t> data;
 
     void createDataFromFile(const char* const datafile, int protocol);
@@ -365,12 +372,11 @@
         createDataFromFile("simplequery_fromWire");
         data[2] = ((i << 3) & 0xff);
 
-        parse_message.clear(Message::PARSE);
-        bool done;
-        server.processMessage(*io_message, parse_message, response_renderer,
-                              &noOp, done);
-    EXPECT_TRUE(done);
-        headerCheck(parse_message, default_qid, Rcode::NOTIMP(), i, QR_FLAG,
+        parse_message->clear(Message::PARSE);
+        server.processMessage(*io_message, parse_message, response_obuffer,
+                              &task);
+    EXPECT_TRUE(task.hasAnswer());
+        headerCheck(*parse_message, default_qid, Rcode::NOTIMP(), i, QR_FLAG,
                     0, 0, 0, 0);
     }
 }
@@ -387,14 +393,12 @@
 // Multiple questions.  Should result in FORMERR.
 TEST_F(AuthSrvTest, multiQuestion) {
     createDataFromFile("multiquestion_fromWire");
-    bool done;
-    server.processMessage(*io_message, parse_message, response_renderer,
-                          &noOp, done);
-    EXPECT_TRUE(done);
-    headerCheck(parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(),
+    server.processMessage(*io_message, parse_message, response_obuffer, &task);
+    EXPECT_TRUE(task.hasAnswer());
+    headerCheck(*parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(),
                 QR_FLAG, 2, 0, 0, 0);
 
-    QuestionIterator qit = parse_message.beginQuestion();
+    QuestionIterator qit = parse_message->beginQuestion();
     EXPECT_EQ(Name("example.com"), (*qit)->getName());
     EXPECT_EQ(RRClass::IN(), (*qit)->getClass());
     EXPECT_EQ(RRType::A(), (*qit)->getType());
@@ -403,17 +407,15 @@
     EXPECT_EQ(RRClass::IN(), (*qit)->getClass());
     EXPECT_EQ(RRType::AAAA(), (*qit)->getType());
     ++qit;
-    EXPECT_TRUE(qit == parse_message.endQuestion());
+    EXPECT_TRUE(qit == parse_message->endQuestion());
 }
 
 // Incoming data doesn't even contain the complete header.  Must be silently
 // dropped.
 TEST_F(AuthSrvTest, shortMessage) {
     createDataFromFile("shortmessage_fromWire");
-    bool done;
-    server.processMessage(*io_message, parse_message, response_renderer,
-                          &noOp, done);
-    EXPECT_FALSE(done);
+    server.processMessage(*io_message, parse_message, response_obuffer, &task);
+    EXPECT_FALSE(task.hasAnswer());
 }
 
 // Response messages.  Must be silently dropped, whether it's a valid response
@@ -421,85 +423,73 @@
 TEST_F(AuthSrvTest, response) {
     // A valid (although unusual) response
     createDataFromFile("simpleresponse_fromWire");
-    bool done;
-    server.processMessage(*io_message, parse_message, response_renderer,
-                          &noOp, done);
-    EXPECT_FALSE(done);
+    server.processMessage(*io_message, parse_message, response_obuffer, &task);
+    EXPECT_FALSE(task.hasAnswer());
 
     // A response with a broken question section.  must be dropped rather than
     // returning FORMERR.
     createDataFromFile("shortresponse_fromWire");
-    server.processMessage(*io_message, parse_message, response_renderer,
-                          &noOp, done);
-    EXPECT_FALSE(done);
+    server.processMessage(*io_message, parse_message, response_obuffer, &task);
+    EXPECT_FALSE(task.hasAnswer());
 
     // A response to iquery.  must be dropped rather than returning NOTIMP.
     createDataFromFile("iqueryresponse_fromWire");
-    server.processMessage(*io_message, parse_message, response_renderer,
-                          &noOp, done);
-    EXPECT_FALSE(done);
+    server.processMessage(*io_message, parse_message, response_obuffer, &task);
+    EXPECT_FALSE(task.hasAnswer());
 }
 
 // Query with a broken question
 TEST_F(AuthSrvTest, shortQuestion) {
     createDataFromFile("shortquestion_fromWire");
-    bool done;
-    server.processMessage(*io_message, parse_message, response_renderer,
-                          &noOp, done);
-    EXPECT_TRUE(done);
+    server.processMessage(*io_message, parse_message, response_obuffer, &task);
+    EXPECT_TRUE(task.hasAnswer());
     // Since the query's question is broken, the question section of the
     // response should be empty.
-    headerCheck(parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(),
+    headerCheck(*parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(),
                 QR_FLAG, 0, 0, 0, 0);
 }
 
 // Query with a broken answer section
 TEST_F(AuthSrvTest, shortAnswer) {
     createDataFromFile("shortanswer_fromWire");
-    bool done;
-    server.processMessage(*io_message, parse_message, response_renderer,
-                          &noOp, done);
-    EXPECT_TRUE(done);
+    server.processMessage(*io_message, parse_message, response_obuffer, &task);
+    EXPECT_TRUE(task.hasAnswer());
 
     // This is a bogus query, but question section is valid.  So the response
     // should copy the question section.
-    headerCheck(parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(),
+    headerCheck(*parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(),
                 QR_FLAG, 1, 0, 0, 0);
 
-    QuestionIterator qit = parse_message.beginQuestion();
+    QuestionIterator qit = parse_message->beginQuestion();
     EXPECT_EQ(Name("example.com"), (*qit)->getName());
     EXPECT_EQ(RRClass::IN(), (*qit)->getClass());
     EXPECT_EQ(RRType::A(), (*qit)->getType());
     ++qit;
-    EXPECT_TRUE(qit == parse_message.endQuestion());
+    EXPECT_TRUE(qit == parse_message->endQuestion());
 }
 
 // Query with unsupported version of EDNS.
 TEST_F(AuthSrvTest, ednsBadVers) {
     createDataFromFile("queryBadEDNS_fromWire");
-    bool done;
-    server.processMessage(*io_message, parse_message, response_renderer,
-                          &noOp, done);
-    EXPECT_TRUE(done);
+    server.processMessage(*io_message, parse_message, response_obuffer, &task);
+    EXPECT_TRUE(task.hasAnswer());
 
     // The response must have an EDNS OPT RR in the additional section.
     // Note that the DNSSEC DO bit is cleared even if this bit in the query
     // is set.  This is a limitation of the current implementation.
-    headerCheck(parse_message, default_qid, Rcode::BADVERS(), opcode.getCode(),
+    headerCheck(*parse_message, default_qid, Rcode::BADVERS(), opcode.getCode(),
                 QR_FLAG, 1, 0, 0, 1);
-    EXPECT_EQ(4096, parse_message.getUDPSize());
-    EXPECT_FALSE(parse_message.isDNSSECSupported());
+    EXPECT_EQ(4096, parse_message->getUDPSize());
+    EXPECT_FALSE(parse_message->isDNSSECSupported());
 }
 
 TEST_F(AuthSrvTest, AXFROverUDP) {
     // AXFR over UDP is invalid and should result in FORMERR.
     createRequestPacket(opcode, Name("example.com"), RRClass::IN(),
                         RRType::AXFR(), IPPROTO_UDP);
-    bool done;
-    server.processMessage(*io_message, parse_message, response_renderer,
-                          &noOp, done);
-    EXPECT_TRUE(done);
-    headerCheck(parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(),
+    server.processMessage(*io_message, parse_message, response_obuffer, &task);
+    EXPECT_TRUE(task.hasAnswer());
+    headerCheck(*parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(),
                 QR_FLAG, 1, 0, 0, 0);
 }
 
@@ -509,10 +499,8 @@
                         RRType::AXFR(), IPPROTO_TCP);
     // On success, the AXFR query has been passed to a separate process,
     // so we shouldn't have to respond.
-    bool done;
-    server.processMessage(*io_message, parse_message, response_renderer,
-                          &noOp, done);
-    EXPECT_FALSE(done);
+    server.processMessage(*io_message, parse_message, response_obuffer, &task);
+    EXPECT_FALSE(task.hasAnswer());
     EXPECT_FALSE(xfrout.isConnected());
 }
 
@@ -521,11 +509,9 @@
     xfrout.disableConnect();
     createRequestPacket(opcode, Name("example.com"), RRClass::IN(),
                         RRType::AXFR(), IPPROTO_TCP);
-    bool done;
-    server.processMessage(*io_message, parse_message, response_renderer,
-                          &noOp, done);
-    EXPECT_TRUE(done);
-    headerCheck(parse_message, default_qid, Rcode::SERVFAIL(),
+    server.processMessage(*io_message, parse_message, response_obuffer, &task);
+    EXPECT_TRUE(task.hasAnswer());
+    headerCheck(*parse_message, default_qid, Rcode::SERVFAIL(),
                 opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
     // For a shot term workaround with xfrout we currently close the connection
     // for each AXFR attempt
@@ -537,20 +523,17 @@
     // open.
     createRequestPacket(opcode, Name("example.com"), RRClass::IN(),
                         RRType::AXFR(), IPPROTO_TCP);
-    bool done;
-    server.processMessage(*io_message, parse_message, response_renderer,
-                          &noOp, done);
+    server.processMessage(*io_message, parse_message, response_obuffer, &task);
     EXPECT_FALSE(xfrout.isConnected()); // see above
 
     xfrout.disableSend();
-    parse_message.clear(Message::PARSE);
-    response_renderer.clear();
+    parse_message->clear(Message::PARSE);
+    response_obuffer->clear();
     createRequestPacket(opcode, Name("example.com"), RRClass::IN(),
                         RRType::AXFR(), IPPROTO_TCP);
-    server.processMessage(*io_message, parse_message, response_renderer,
-                          &noOp, done);
-    EXPECT_TRUE(done);
-    headerCheck(parse_message, default_qid, Rcode::SERVFAIL(),
+    server.processMessage(*io_message, parse_message, response_obuffer, &task);
+    EXPECT_TRUE(task.hasAnswer());
+    headerCheck(*parse_message, default_qid, Rcode::SERVFAIL(),
                 opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
 
     // The connection should have been closed due to the send failure.
@@ -564,9 +547,8 @@
     xfrout.disableDisconnect();
     createRequestPacket(opcode, Name("example.com"), RRClass::IN(),
                         RRType::AXFR(), IPPROTO_TCP);
-    bool done;
     EXPECT_THROW(server.processMessage(*io_message, parse_message,
-                                       response_renderer, &noOp, done),
+                                       response_obuffer, &task),
                  XfroutError);
     EXPECT_TRUE(xfrout.isConnected());
     // XXX: we need to re-enable disconnect.  otherwise an exception would be
@@ -579,10 +561,8 @@
                         RRType::SOA());
     request_message.setHeaderFlag(MessageFlag::AA());
     createRequestPacket(IPPROTO_UDP);
-    bool done;
-    server.processMessage(*io_message, parse_message, response_renderer,
-                          &noOp, done);
-    EXPECT_TRUE(done);
+    server.processMessage(*io_message, parse_message, response_obuffer, &task);
+    EXPECT_TRUE(task.hasAnswer());
 
     // An internal command message should have been created and sent to an
     // external module.  Check them.
@@ -597,11 +577,11 @@
     EXPECT_EQ("IN", notify_args->get("zone_class")->stringValue());
 
     // On success, the server should return a response to the notify.
-    headerCheck(parse_message, default_qid, Rcode::NOERROR(),
+    headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
                 Opcode::NOTIFY().getCode(), QR_FLAG | AA_FLAG, 1, 0, 0, 0);
 
     // The question must be identical to that of the received notify
-    ConstQuestionPtr question = *parse_message.beginQuestion();
+    ConstQuestionPtr question = *parse_message->beginQuestion();
     EXPECT_EQ(Name("example.com"), question->getName());
     EXPECT_EQ(RRClass::IN(), question->getClass());
     EXPECT_EQ(RRType::SOA(), question->getType());
@@ -613,10 +593,8 @@
                         RRType::SOA());
     request_message.setHeaderFlag(MessageFlag::AA());
     createRequestPacket(IPPROTO_UDP);
-    bool done;
-    server.processMessage(*io_message, parse_message, response_renderer,
-                          &noOp, done);
-    EXPECT_TRUE(done);
+    server.processMessage(*io_message, parse_message, response_obuffer, &task);
+    EXPECT_TRUE(task.hasAnswer());
 
     // Other conditions should be the same, so simply confirm the RR class is
     // set correctly.
@@ -632,11 +610,9 @@
     request_message.setQid(default_qid);
     request_message.toWire(request_renderer);
     createRequestPacket(IPPROTO_UDP);
-    bool done;
-    server.processMessage(*io_message, parse_message, response_renderer,
-                          &noOp, done);
-    EXPECT_TRUE(done);
-    headerCheck(parse_message, default_qid, Rcode::FORMERR(),
+    server.processMessage(*io_message, parse_message, response_obuffer, &task);
+    EXPECT_TRUE(task.hasAnswer());
+    headerCheck(*parse_message, default_qid, Rcode::FORMERR(),
                 Opcode::NOTIFY().getCode(), QR_FLAG, 0, 0, 0, 0);
 }
 
@@ -648,11 +624,9 @@
                                          RRType::SOA()));
     request_message.setHeaderFlag(MessageFlag::AA());
     createRequestPacket(IPPROTO_UDP);
-    bool done;
-    server.processMessage(*io_message, parse_message, response_renderer,
-                          &noOp, done);
-    EXPECT_TRUE(done);
-    headerCheck(parse_message, default_qid, Rcode::FORMERR(),
+    server.processMessage(*io_message, parse_message, response_obuffer, &task);
+    EXPECT_TRUE(task.hasAnswer());
+    headerCheck(*parse_message, default_qid, Rcode::FORMERR(),
                 Opcode::NOTIFY().getCode(), QR_FLAG, 2, 0, 0, 0);
 }
 
@@ -661,11 +635,9 @@
                         RRType::NS());
     request_message.setHeaderFlag(MessageFlag::AA());
     createRequestPacket(IPPROTO_UDP);
-    bool done;
-    server.processMessage(*io_message, parse_message, response_renderer,
-                          &noOp, done);
-    EXPECT_TRUE(done);
-    headerCheck(parse_message, default_qid, Rcode::FORMERR(),
+    server.processMessage(*io_message, parse_message, response_obuffer, &task);
+    EXPECT_TRUE(task.hasAnswer());
+    headerCheck(*parse_message, default_qid, Rcode::FORMERR(),
                 Opcode::NOTIFY().getCode(), QR_FLAG, 1, 0, 0, 0);
 }
 
@@ -673,11 +645,9 @@
     // implicitly leave the AA bit off.  our implementation will accept it.
     createRequestPacket(Opcode::NOTIFY(), Name("example.com"), RRClass::IN(),
                         RRType::SOA());
-    bool done;
-    server.processMessage(*io_message, parse_message, response_renderer,
-                          &noOp, done);
-    EXPECT_TRUE(done);
-    headerCheck(parse_message, default_qid, Rcode::NOERROR(),
+    server.processMessage(*io_message, parse_message, response_obuffer, &task);
+    EXPECT_TRUE(task.hasAnswer());
+    headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
                 Opcode::NOTIFY().getCode(), QR_FLAG | AA_FLAG, 1, 0, 0, 0);
 }
 
@@ -687,11 +657,9 @@
     request_message.setHeaderFlag(MessageFlag::AA());
     request_message.setRcode(Rcode::SERVFAIL());
     createRequestPacket(IPPROTO_UDP);
-    bool done;
-    server.processMessage(*io_message, parse_message, response_renderer,
-                          &noOp, done);
-    EXPECT_TRUE(done);
-    headerCheck(parse_message, default_qid, Rcode::NOERROR(),
+    server.processMessage(*io_message, parse_message, response_obuffer, &task);
+    EXPECT_TRUE(task.hasAnswer());
+    headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
                 Opcode::NOTIFY().getCode(), QR_FLAG | AA_FLAG, 1, 0, 0, 0);
 }
 
@@ -705,10 +673,8 @@
 
     // we simply ignore the notify and let it be resent if an internal error
     // happens.
-    bool done;
-    server.processMessage(*io_message, parse_message, response_renderer,
-                          &noOp, done);
-    EXPECT_FALSE(done);
+    server.processMessage(*io_message, parse_message, response_obuffer, &task);
+    EXPECT_FALSE(task.hasAnswer());
 }
 
 TEST_F(AuthSrvTest, notifySendFail) {
@@ -719,10 +685,8 @@
     request_message.setHeaderFlag(MessageFlag::AA());
     createRequestPacket(IPPROTO_UDP);
 
-    bool done;
-    server.processMessage(*io_message, parse_message, response_renderer,
-                          &noOp, done);
-    EXPECT_FALSE(done);
+    server.processMessage(*io_message, parse_message, response_obuffer, &task);
+    EXPECT_FALSE(task.hasAnswer());
 }
 
 TEST_F(AuthSrvTest, notifyReceiveFail) {
@@ -732,10 +696,8 @@
                         RRType::SOA());
     request_message.setHeaderFlag(MessageFlag::AA());
     createRequestPacket(IPPROTO_UDP);
-    bool done;
-    server.processMessage(*io_message, parse_message, response_renderer,
-                          &noOp, done);
-    EXPECT_FALSE(done);
+    server.processMessage(*io_message, parse_message, response_obuffer, &task);
+    EXPECT_FALSE(task.hasAnswer());
 }
 
 TEST_F(AuthSrvTest, notifyWithBogusSessionMessage) {
@@ -745,10 +707,8 @@
                         RRType::SOA());
     request_message.setHeaderFlag(MessageFlag::AA());
     createRequestPacket(IPPROTO_UDP);
-    bool done;
-    server.processMessage(*io_message, parse_message, response_renderer,
-                          &noOp, done);
-    EXPECT_FALSE(done);
+    server.processMessage(*io_message, parse_message, response_obuffer, &task);
+    EXPECT_FALSE(task.hasAnswer());
 }
 
 TEST_F(AuthSrvTest, notifyWithSessionMessageError) {
@@ -759,10 +719,8 @@
                         RRType::SOA());
     request_message.setHeaderFlag(MessageFlag::AA());
     createRequestPacket(IPPROTO_UDP);
-    bool done;
-    server.processMessage(*io_message, parse_message, response_renderer,
-                          &noOp, done);
-    EXPECT_FALSE(done);
+    server.processMessage(*io_message, parse_message, response_obuffer, &task);
+    EXPECT_FALSE(task.hasAnswer());
 }
 
 void
@@ -787,11 +745,9 @@
     // response should have the AA flag on, and have an RR in each answer
     // and authority section.
     createDataFromFile("examplequery_fromWire");
-    bool done;
-    server.processMessage(*io_message, parse_message, response_renderer,
-                          &noOp, done);
-    EXPECT_TRUE(done);
-    headerCheck(parse_message, default_qid, Rcode::NOERROR(), opcode.getCode(),
+    server.processMessage(*io_message, parse_message, response_obuffer, &task);
+    EXPECT_TRUE(task.hasAnswer());
+    headerCheck(*parse_message, default_qid, Rcode::NOERROR(), opcode.getCode(),
                 QR_FLAG | AA_FLAG, 1, 1, 1, 0);
 }
 
@@ -803,11 +759,9 @@
     // in a SERVFAIL response, and the answer and authority sections should
     // be empty.
     createDataFromFile("badExampleQuery_fromWire");
-    bool done;
-    server.processMessage(*io_message, parse_message, response_renderer,
-                          &noOp, done);
-    EXPECT_TRUE(done);
-    headerCheck(parse_message, default_qid, Rcode::SERVFAIL(),
+    server.processMessage(*io_message, parse_message, response_obuffer, &task);
+    EXPECT_TRUE(task.hasAnswer());
+    headerCheck(*parse_message, default_qid, Rcode::SERVFAIL(),
                 opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
 }
 
@@ -820,11 +774,9 @@
 
     // The original data source should still exist.
     createDataFromFile("examplequery_fromWire");
-    bool done;
-    server.processMessage(*io_message, parse_message, response_renderer,
-                          &noOp, done);
-    EXPECT_TRUE(done);
-    headerCheck(parse_message, default_qid, Rcode::NOERROR(), opcode.getCode(),
+    server.processMessage(*io_message, parse_message, response_obuffer, &task);
+    EXPECT_TRUE(task.hasAnswer());
+    headerCheck(*parse_message, default_qid, Rcode::NOERROR(), opcode.getCode(),
                 QR_FLAG | AA_FLAG, 1, 1, 1, 0);
 }
 }

Modified: branches/trac327/src/bin/bind10/bind10.py.in
==============================================================================
--- branches/trac327/src/bin/bind10/bind10.py.in (original)
+++ branches/trac327/src/bin/bind10/bind10.py.in Sun Oct  3 06:44:36 2010
@@ -202,8 +202,9 @@
 class BoB:
     """Boss of BIND class."""
     
-    def __init__(self, msgq_socket_file=None, auth_port=5300, address='',
-                 nocache=False, verbose=False, setuid=None, username=None):
+    def __init__(self, msgq_socket_file=None, dns_port=5300, address='',
+                 forward=None, nocache=False, verbose=False, setuid=None,
+                 username=None):
         """Initialize the Boss of BIND. This is a singleton (only one
         can run).
         
@@ -213,10 +214,17 @@
         """
         self.verbose = verbose
         self.msgq_socket_file = msgq_socket_file
-        self.auth_port = auth_port
+        self.dns_port = dns_port
         self.address = None
+        self.nocache = nocache
         if address:
             self.address = IPAddr(address)
+        self.forward = None
+        self.recursive = False
+        if forward:
+            self.forward = IPAddr(forward)
+            self.recursive = True
+            self.nocache = False
         self.cc_session = None
         self.ccs = None
         self.processes = {}
@@ -224,7 +232,6 @@
         self.runnable = False
         self.uid = setuid
         self.username = username
-        self.nocache = nocache
 
     def config_handler(self, new_config):
         if self.verbose:
@@ -329,94 +336,111 @@
         if self.verbose:
             sys.stdout.write("[bind10] ccsession started\n")
 
-        # start b10-auth
+        # if we're running a recursive-only server, we skip the xfrout
+        # modules. otherwise, start xfrout before the DNS server, to make
+        # sure every xfr-query can be processed properly.
+        xfrout=None
+        if not self.recursive:
+            xfrout_args = ['b10-xfrout']
+            if self.verbose:
+                sys.stdout.write("[bind10] Starting b10-xfrout\n")
+                xfrout_args += ['-v']
+            try:
+                xfrout = ProcessInfo("b10-xfrout", xfrout_args, 
+                                     c_channel_env )
+            except Exception as e:
+                c_channel.process.kill()
+                bind_cfgd.process.kill()
+                return "Unable to start b10-xfrout; " + str(e)
+            self.processes[xfrout.pid] = xfrout
+            if self.verbose:
+                sys.stdout.write("[bind10] Started b10-xfrout (PID %d)\n" % 
+                                 xfrout.pid)
+
+        # start DNS server
         # XXX: this must be read from the configuration manager in the future
-        authargs = ['b10-auth', '-p', str(self.auth_port)]
+        if self.recursive:
+            dns_prog = 'b10-recurse'
+        else:
+            dns_prog = 'b10-auth'
+        dnsargs = [dns_prog, '-p', str(self.dns_port)]
+        if self.forward:
+            dnsargs += ['-f', str(self.forward)]
         if self.address:
-            authargs += ['-a', str(self.address)]
+            dnsargs += ['-a', str(self.address)]
         if self.nocache:
-            authargs += ['-n']
+            dnsargs += ['-n']
         if self.uid:
-            authargs += ['-u', str(self.uid)]
-        if self.verbose:
-            authargs += ['-v']
-            sys.stdout.write("Starting b10-auth using port %d" %
-                             self.auth_port)
+            dnsargs += ['-u', str(self.uid)]
+        if self.verbose:
+            dnsargs += ['-v']
+            sys.stdout.write("Starting %s using port %d" %
+                             (dns_prog, self.dns_port))
             if self.address:
                 sys.stdout.write(" on %s" % str(self.address))
             sys.stdout.write("\n")
         try:
-            auth = ProcessInfo("b10-auth", authargs,
-                               c_channel_env)
+            dns = ProcessInfo(dns_prog, dnsargs, c_channel_env)
         except Exception as e:
             c_channel.process.kill()
             bind_cfgd.process.kill()
-            xfrout.process.kill()
-            return "Unable to start b10-auth; " + str(e)
-        self.processes[auth.pid] = auth
-        if self.verbose:
-            sys.stdout.write("[bind10] Started b10-auth (PID %d)\n" % auth.pid)
-
-        # everything after the authoritative server can run as non-root
+            if xfrout:
+                xfrout.process.kill()
+            return "Unable to start " + dns_prog + ": " + str(e)
+        self.processes[dns.pid] = dns
+        if self.verbose:
+            sys.stdout.write("[bind10] Started %s (PID %d)\n" %
+                             (dns_prog, dns.pid))
+
+        # everything after the DNS server can run as non-root
         if self.uid is not None:
             posix.setuid(self.uid)
 
-        # start the xfrout before auth-server, to make sure every xfr-query can
-        # be processed properly.
-        xfrout_args = ['b10-xfrout']
-        if self.verbose:
-            sys.stdout.write("[bind10] Starting b10-xfrout\n")
-            xfrout_args += ['-v']
-        try:
-            xfrout = ProcessInfo("b10-xfrout", xfrout_args, 
-                                 c_channel_env )
-        except Exception as e:
-            c_channel.process.kill()
-            bind_cfgd.process.kill()
-            return "Unable to start b10-xfrout; " + str(e)
-        self.processes[xfrout.pid] = xfrout
-        if self.verbose:
-            sys.stdout.write("[bind10] Started b10-xfrout (PID %d)\n" % 
-                             xfrout.pid)
-
-        # start b10-xfrin
-        xfrin_args = ['b10-xfrin']
-        if self.verbose:
-            sys.stdout.write("[bind10] Starting b10-xfrin\n")
-            xfrin_args += ['-v']
-        try:
-            xfrind = ProcessInfo("b10-xfrin", xfrin_args,
-                                 c_channel_env)
-        except Exception as e:
-            c_channel.process.kill()
-            bind_cfgd.process.kill()
-            xfrout.process.kill()
-            auth.process.kill()
-            return "Unable to start b10-xfrin; " + str(e)
-        self.processes[xfrind.pid] = xfrind
-        if self.verbose:
-            sys.stdout.write("[bind10] Started b10-xfrin (PID %d)\n" % 
-                             xfrind.pid)
-
-        # start b10-zonemgr
-        zonemgr_args = ['b10-zonemgr']
-        if self.verbose:
-            sys.stdout.write("[bind10] Starting b10-zonemgr\n")
-            zonemgr_args += ['-v']
-        try:
-            zonemgr = ProcessInfo("b10-zonemgr", zonemgr_args,
-                                 c_channel_env)
-        except Exception as e:
-            c_channel.process.kill()
-            bind_cfgd.process.kill()
-            xfrout.process.kill()
-            auth.process.kill()
-            xfrind.process.kill()
-            return "Unable to start b10-zonemgr; " + str(e)
-        self.processes[zonemgr.pid] = zonemgr 
-        if self.verbose:
-            sys.stdout.write("[bind10] Started b10-zonemgr(PID %d)\n" % 
-                             zonemgr.pid)
+        xfrind=None
+        if not self.recursive:
+            # If we're running an authoritative server, start b10-xfrin
+            xfrin_args = ['b10-xfrin']
+            if self.verbose:
+                sys.stdout.write("[bind10] Starting b10-xfrin\n")
+                xfrin_args += ['-v']
+            try:
+                xfrind = ProcessInfo("b10-xfrin", xfrin_args,
+                                     c_channel_env)
+            except Exception as e:
+                c_channel.process.kill()
+                bind_cfgd.process.kill()
+                if xfrout:
+                    xfrout.process.kill()
+                dns.process.kill()
+                return "Unable to start b10-xfrin; " + str(e)
+            self.processes[xfrind.pid] = xfrind
+            if self.verbose:
+                sys.stdout.write("[bind10] Started b10-xfrin (PID %d)\n" % 
+                                 xfrind.pid)
+
+        zonemgr=None
+        if not self.recursive:
+            # If we're running an authoritative server, start b10-zonemgr
+            zonemgr_args = ['b10-zonemgr']
+            if self.verbose:
+                sys.stdout.write("[bind10] Starting b10-zonemgr\n")
+                zonemgr_args += ['-v']
+            try:
+                zonemgr = ProcessInfo("b10-zonemgr", zonemgr_args,
+                                     c_channel_env)
+            except Exception as e:
+                c_channel.process.kill()
+                bind_cfgd.process.kill()
+                dns.process.kill()
+                if xfrout:
+                    xfrout.process.kill()
+                if xfrind:
+                    xfrind.process.kill()
+                return "Unable to start b10-zonemgr; " + str(e)
+            self.processes[zonemgr.pid] = zonemgr 
+            if self.verbose:
+                sys.stdout.write("[bind10] Started b10-zonemgr(PID %d)\n" % 
+                                 zonemgr.pid)
 
         # start the b10-cmdctl
         # XXX: we hardcode port 8080
@@ -430,10 +454,13 @@
         except Exception as e:
             c_channel.process.kill()
             bind_cfgd.process.kill()
-            xfrout.process.kill()
-            auth.process.kill()
-            xfrind.process.kill()
-            zonemgr.process.kill()
+            dns.process.kill()
+            if xfrout:
+                xfrout.process.kill()
+            if xfrind:
+                xfrind.process.kill()
+            if zonemgr:
+                zonemgr.process.kill()
             return "Unable to start b10-cmdctl; " + str(e)
         self.processes[cmd_ctrld.pid] = cmd_ctrld
         if self.verbose:
@@ -450,6 +477,7 @@
         self.cc_session.group_sendmsg(cmd, 'Boss', 'Cmdctl')
         self.cc_session.group_sendmsg(cmd, "Boss", "ConfigManager")
         self.cc_session.group_sendmsg(cmd, "Boss", "Auth")
+        self.cc_session.group_sendmsg(cmd, "Boss", "Recurse")
         self.cc_session.group_sendmsg(cmd, "Boss", "Xfrout")
         self.cc_session.group_sendmsg(cmd, "Boss", "Xfrin")
         self.cc_session.group_sendmsg(cmd, "Boss", "Zonemgr")
@@ -603,7 +631,7 @@
     if (opt_str == '-m' or opt_str == '--msgq-port'):
         parser.values.msgq_port = value
     elif (opt_str == '-p' or opt_str == '--port'):
-        parser.values.auth_port = value
+        parser.values.dns_port = value
     else:
         raise OptionValueError("Unknown option " + opt_str)
   
@@ -616,6 +644,8 @@
         raise OptionValueError("%s requires a valid IPv4 or IPv6 address" % opt_str)
     if (opt_str == '-a' or opt_str == '--address'):
         parser.values.address = value
+    elif (opt_str == '-f' or opt_str == '--forward'):
+        parser.values.forward = value
     else:
         raise OptionValueError("Unknown option " + opt_str)
   
@@ -625,22 +655,23 @@
     # Enforce line buffering on stdout, even when not a TTY
     sys.stdout = io.TextIOWrapper(sys.stdout.detach(), line_buffering=True)
 
-
     # Parse any command-line options.
     parser = OptionParser(version=__version__)
     parser.add_option("-a", "--address", dest="address", type="string",
                       action="callback", callback=check_addr, default='',
-                      help="address the b10-auth daemon will use (default: listen on all addresses)")
+                      help="address the DNS server will use (default: listen on all addresses)")
+    parser.add_option("-f", "--forward", dest="forward", type="string",
+                      action="callback", callback=check_addr, default='',
+                      help="nameserver to which DNS queries should be forwarded")
     parser.add_option("-m", "--msgq-socket-file", dest="msgq_socket_file",
                       type="string", default=None,
                       help="UNIX domain socket file the b10-msgq daemon will use")
     parser.add_option("-n", "--no-cache", action="store_true", dest="nocache",
-                      default=False, help="disable hot-spot cache in b10-auth")
-    parser.add_option("-p", "--port", dest="auth_port", type="string",
+                      default=False, help="disable hot-spot cache in authoritative DNS server")
+    parser.add_option("-p", "--port", dest="dns_port", type="string",
                       action="callback", callback=check_port, default="5300",
-                      help="port the b10-auth daemon will use (default 5300)")
-    parser.add_option("-u", "--user", dest="user",
-                      type="string", default=None,
+                      help="port the DNS server will use (default 5300)")
+    parser.add_option("-u", "--user", dest="user", type="string", default=None,
                       help="Change user after startup (must run as root)")
     parser.add_option("-v", "--verbose", dest="verbose", action="store_true",
                       help="display more about what is going on")
@@ -698,9 +729,9 @@
     signal.signal(signal.SIGTERM, fatal_signal)
 
     # Go bob!
-    boss_of_bind = BoB(options.msgq_socket_file, int(options.auth_port),
-                       options.address, options.nocache, options.verbose,
-                       setuid, username)
+    boss_of_bind = BoB(options.msgq_socket_file, int(options.dns_port),
+                       options.address, options.forward, options.nocache,
+                       options.verbose, setuid, username)
     startup_result = boss_of_bind.startup()
     if startup_result:
         sys.stderr.write("[bind10] Error on startup: %s\n" % startup_result)

Modified: branches/trac327/src/bin/bind10/run_bind10.sh.in
==============================================================================
--- branches/trac327/src/bin/bind10/run_bind10.sh.in (original)
+++ branches/trac327/src/bin/bind10/run_bind10.sh.in Sun Oct  3 06:44:36 2010
@@ -20,7 +20,7 @@
 
 BIND10_PATH=@abs_top_builddir@/src/bin/bind10
 
-PATH=@abs_top_builddir@/src/bin/msgq:@abs_top_builddir@/src/bin/auth:@abs_top_builddir@/src/bin/cfgmgr:@abs_top_builddir@/src/bin/cmdctl:@abs_top_builddir@/src/bin/xfrin:@abs_top_builddir@/src/bin/xfrout:@abs_top_builddir@/src/bin/zonemgr:$PATH
+PATH=@abs_top_builddir@/src/bin/msgq:@abs_top_builddir@/src/bin/auth:@abs_top_builddir@/src/bin/recurse:@abs_top_builddir@/src/bin/cfgmgr:@abs_top_builddir@/src/bin/cmdctl:@abs_top_builddir@/src/bin/xfrin:@abs_top_builddir@/src/bin/xfrout:@abs_top_builddir@/src/bin/zonemgr:$PATH
 export PATH
 
 PYTHONPATH=@abs_top_builddir@/src/lib/python:@abs_top_builddir@/src/lib/dns/python/.libs:@abs_top_builddir@/src/lib/xfr/.libs

Modified: branches/trac327/src/bin/recurse/main.cc
==============================================================================
--- branches/trac327/src/bin/recurse/main.cc (original)
+++ branches/trac327/src/bin/recurse/main.cc Sun Oct  3 06:44:36 2010
@@ -86,7 +86,8 @@
 
 void
 usage() {
-    cerr << "Usage: b10-recurse [-a address] [-p port] [-4|-6] [-nv]" << endl;
+    cerr << "Usage: b10-recurse -f nameserver [-a address] [-p port] "
+            "[-4|-6] [-nv]" << endl;
     exit(1);
 }
 } // end of anonymous namespace
@@ -96,10 +97,11 @@
     int ch;
     const char* port = DNSPORT;
     const char* address = NULL;
+    const char* forward = NULL;
     const char* uid = NULL;
     bool use_ipv4 = true, use_ipv6 = true, cache = true;
 
-    while ((ch = getopt(argc, argv, "46a:np:u:v")) != -1) {
+    while ((ch = getopt(argc, argv, "46a:f:np:u:v")) != -1) {
         switch (ch) {
         case '4':
             // Note that -4 means "ipv4 only", we need to set "use_ipv6" here,
@@ -118,6 +120,9 @@
         case 'a':
             address = optarg;
             break;
+        case 'f':
+            forward = optarg;
+            break;
         case 'p':
             port = optarg;
             break;
@@ -144,6 +149,11 @@
 
     if ((!use_ipv4 || !use_ipv6) && address != NULL) {
         cerr << "[b10-recurse] Error: -4|-6 and -a can't coexist" << endl;
+        usage();
+    }
+
+    if (forward == NULL) {
+        cerr << "[b10-recurse] No forward name server specified" << endl;
         usage();
     }
 
@@ -160,6 +170,10 @@
         } else {
             specfile = string(RECURSE_SPECFILE_LOCATION);
         }
+
+        recursor = new Recursor(*forward);
+        recursor ->setVerbose(verbose_mode);
+        cout << "[b10-recurse] Server created." << endl;
 
         IOCallback* checkin = recursor->getCheckinProvider();
         DNSLookup* lookup = recursor->getDNSLookupProvider();
@@ -178,11 +192,8 @@
             io_service = new IOService(*port, use_ipv4, use_ipv6,
                                        checkin, lookup, answer);
         }
+        recursor->setIOService(*io_service);
         cout << "[b10-recurse] IOService created." << endl;
-
-        recursor = new Recursor(*io_service);
-        recursor ->setVerbose(verbose_mode);
-        cout << "[b10-recurse] Server created." << endl;
 
         cc_session = new Session(io_service->get_io_service());
         cout << "[b10-recurse] Configuration session channel created." << endl;

Modified: branches/trac327/src/bin/recurse/recursor.cc
==============================================================================
--- branches/trac327/src/bin/recurse/recursor.cc (original)
+++ branches/trac327/src/bin/recurse/recursor.cc Sun Oct  3 06:44:36 2010
@@ -25,6 +25,8 @@
 
 #include <asiolink/asiolink.h>
 
+#include <boost/foreach.hpp>
+
 #include <config/ccsession.h>
 
 #include <cc/data.h>
@@ -33,7 +35,6 @@
 
 #include <dns/buffer.h>
 #include <dns/exceptions.h>
-#include <dns/messagerenderer.h>
 #include <dns/name.h>
 #include <dns/question.h>
 #include <dns/rrset.h>
@@ -61,25 +62,105 @@
     RecursorImpl(const RecursorImpl& source);
     RecursorImpl& operator=(const RecursorImpl& source);
 public:
-    RecursorImpl(asiolink::IOService& io_service);
-    bool processNormalQuery(const IOMessage& io_message,
-                            const Question& question, Message& message,
-                            MessageRenderer& renderer,
-                            BasicServer* server);
+    RecursorImpl(const char& forward) :
+        config_session_(NULL), verbose_mode_(false),
+        forward_(forward), ioquery_()
+    {}
+
+    ~RecursorImpl() {
+        queryShutdown();
+    }
+
+    void querySetup(IOService& ios) {
+        ioquery_ = new IOQuery(ios, forward_);
+    }
+
+    void queryShutdown() {
+        if (ioquery_) {
+            delete ioquery_;
+        }
+    }
+
+    void processNormalQuery(const IOMessage& io_message,
+                            const Question& question, MessagePtr message,
+                            OutputBufferPtr buffer,
+                            IOServer* server);
     ModuleCCSession* config_session_;
 
     bool verbose_mode_;
 
+    /// Address of the forward nameserver
+    const char& forward_;
+
     /// Object to handle upstream queries
-    IOQuery ioquery_;
+    IOQuery* ioquery_;
 
     /// Currently non-configurable, but will be.
     static const uint16_t DEFAULT_LOCAL_UDPSIZE = 4096;
 };
 
-RecursorImpl::RecursorImpl(asiolink::IOService& io_service) :
-    config_session_(NULL), verbose_mode_(false), ioquery_(io_service)
-{}
+class QuestionInserter {
+public:
+    QuestionInserter(MessagePtr message) : message_(message) {}
+    void operator()(const QuestionPtr question) {
+        message_->addQuestion(question);
+    }
+    MessagePtr message_;
+};
+
+class SectionInserter {
+public:
+    SectionInserter(MessagePtr message, const Section& sect, bool sign) :
+        message_(message), section_(sect), sign_(sign)
+    {}
+    void operator()(const RRsetPtr rrset) {
+        message_->addRRset(section_, rrset, true);
+    }
+    MessagePtr message_;
+    const Section& section_;
+    bool sign_;
+};
+
+void
+makeErrorMessage(MessagePtr message, OutputBufferPtr buffer,
+                 const Rcode& rcode, const bool verbose_mode)
+{
+    // extract the parameters that should be kept.
+    // XXX: with the current implementation, it's not easy to set EDNS0
+    // depending on whether the query had it.  So we'll simply omit it.
+    const qid_t qid = message->getQid();
+    const bool rd = message->getHeaderFlag(MessageFlag::RD());
+    const bool cd = message->getHeaderFlag(MessageFlag::CD());
+    const Opcode& opcode = message->getOpcode();
+    vector<QuestionPtr> questions;
+
+    // If this is an error to a query or notify, we should also copy the
+    // question section.
+    if (opcode == Opcode::QUERY() || opcode == Opcode::NOTIFY()) {
+        questions.assign(message->beginQuestion(), message->endQuestion());
+    }
+
+    message->clear(Message::RENDER);
+    message->setQid(qid);
+    message->setOpcode(opcode);
+    message->setHeaderFlag(MessageFlag::QR());
+    message->setUDPSize(RecursorImpl::DEFAULT_LOCAL_UDPSIZE);
+    if (rd) {
+        message->setHeaderFlag(MessageFlag::RD());
+    }
+    if (cd) {
+        message->setHeaderFlag(MessageFlag::CD());
+    }
+    for_each(questions.begin(), questions.end(), QuestionInserter(message));
+    message->setRcode(rcode);
+    MessageRenderer renderer(*buffer);
+    message->toWire(renderer);
+
+    if (verbose_mode) {
+        cerr << "[b10-recurse] sending an error response (" <<
+            renderer.getLength() << " bytes):\n" << message->toText() << endl;
+    }
+}
 
 // This is a derived class of \c DNSLookup, to serve as a
 // callback in the asiolink module.  It calls
@@ -87,13 +168,12 @@
 class MessageLookup : public DNSLookup {
 public:
     MessageLookup(Recursor* srv) : server_(srv) {}
-    virtual void operator()(const IOMessage& io_message,
-                            isc::dns::Message& dns_message,
-                            isc::dns::MessageRenderer& renderer,
-                            BasicServer* server, bool& complete) const
+
+    // \brief Handle the DNS Lookup
+    virtual void operator()(const IOMessage& io_message, MessagePtr message,
+                            OutputBufferPtr buffer, IOServer* server) const
     {
-        server_->processMessage(io_message, dns_message, renderer,
-                                server, complete);
+        server_->processMessage(io_message, message, buffer, server);
     }
 private:
     Recursor* server_;
@@ -107,18 +187,76 @@
 public:
     MessageAnswer(Recursor* srv) : server_(srv) {}
     virtual void operator()(const IOMessage& io_message,
-                            isc::dns::Message& message,
-                            isc::dns::MessageRenderer& renderer) const
+                            MessagePtr message,
+                            OutputBufferPtr buffer) const
     {
+        const qid_t qid = message->getQid();
+        const bool rd = message->getHeaderFlag(MessageFlag::RD());
+        const bool cd = message->getHeaderFlag(MessageFlag::CD());
+        const Opcode& opcode = message->getOpcode();
+        const Rcode& rcode = message->getRcode();
+        vector<QuestionPtr> questions;
+        questions.assign(message->beginQuestion(), message->endQuestion());
+
+        message->clear(Message::RENDER);
+        message->setQid(qid);
+        message->setOpcode(opcode);
+        message->setRcode(rcode);
+        message->setUDPSize(RecursorImpl::DEFAULT_LOCAL_UDPSIZE);
+
+        message->setHeaderFlag(MessageFlag::QR());
+        message->setHeaderFlag(MessageFlag::RA());
+        if (rd) {
+            message->setHeaderFlag(MessageFlag::RD());
+        }
+        if (cd) {
+            message->setHeaderFlag(MessageFlag::CD());
+        }
+
+
+        // Copy the question section.
+        for_each(questions.begin(), questions.end(), QuestionInserter(message));
+
+        // If the buffer already has an answer in it, copy RRsets from
+        // that into the new message, then clear the buffer and render
+        // the new message into it.
+        if (buffer->getLength() != 0) {
+            try {
+                Message incoming(Message::PARSE);
+                InputBuffer ibuf(buffer->getData(), buffer->getLength());
+                incoming.fromWire(ibuf);
+                for_each(incoming.beginSection(Section::ANSWER()), 
+                         incoming.endSection(Section::ANSWER()),
+                         SectionInserter(message, Section::ANSWER(), true));
+                for_each(incoming.beginSection(Section::ADDITIONAL()), 
+                         incoming.endSection(Section::ADDITIONAL()),
+                         SectionInserter(message, Section::ADDITIONAL(), true));
+                for_each(incoming.beginSection(Section::AUTHORITY()), 
+                         incoming.endSection(Section::AUTHORITY()),
+                         SectionInserter(message, Section::AUTHORITY(), true));
+            } catch (const Exception& ex) {
+                // Incoming message couldn't be read, we just SERVFAIL
+                message->setRcode(Rcode::SERVFAIL());
+            }
+
+        }
+
+        // Now we can clear the buffer and render the new message into it
+        buffer->clear();
+        MessageRenderer renderer(*buffer);
+
         if (io_message.getSocket().getProtocol() == IPPROTO_UDP) {
-            renderer.setLengthLimit(message.getUDPSize());
+            renderer.setLengthLimit(message->getUDPSize());
         } else {
             renderer.setLengthLimit(65535);
         }
-        message.toWire(renderer);
+
+        message->toWire(renderer);
+
         if (server_->getVerbose()) {
-            cerr << "[b10-recurse] sending a response (" << renderer.getLength()
-                 << " bytes):\n" << message.toText() << endl;
+            cerr << "[b10-recurse] sending a response ("
+                 << renderer.getLength() << " bytes):\n"
+                 << message->toText() << endl;
         }
     }
 
@@ -129,9 +267,9 @@
 // This is a derived class of \c IOCallback, to serve
 // as a callback in the asiolink module.  It checks for queued
 // configuration messages, and executes them if found.
-class ConfigChecker : public IOCallback {
-public:
-    ConfigChecker(Recursor* srv) : server_(srv) {}
+class ConfigCheck : public IOCallback {
+public:
+    ConfigCheck(Recursor* srv) : server_(srv) {}
     virtual void operator()(const IOMessage& io_message UNUSED_PARAM) const {
         if (server_->configSession()->hasQueuedMsgs()) {
             server_->configSession()->checkCommand();
@@ -141,9 +279,9 @@
     Recursor* server_;
 };
 
-Recursor::Recursor(asiolink::IOService& io_service) :
-    impl_(new RecursorImpl(io_service)),
-    checkin_(new ConfigChecker(this)),
+Recursor::Recursor(const char& forward) :
+    impl_(new RecursorImpl(forward)),
+    checkin_(new ConfigCheck(this)),
     dns_lookup_(new MessageLookup(this)),
     dns_answer_(new MessageAnswer(this))
 {}
@@ -155,55 +293,11 @@
     delete dns_answer_;
 }
 
-namespace {
-class QuestionInserter {
-public:
-    QuestionInserter(Message* message) : message_(message) {}
-    void operator()(const QuestionPtr question) {
-        message_->addQuestion(question);
-    }
-    Message* message_;
-};
-
-void
-makeErrorMessage(Message& message, MessageRenderer& renderer,
-                 const Rcode& rcode, const bool verbose_mode)
-{
-    // extract the parameters that should be kept.
-    // XXX: with the current implementation, it's not easy to set EDNS0
-    // depending on whether the query had it.  So we'll simply omit it.
-    const qid_t qid = message.getQid();
-    const bool rd = message.getHeaderFlag(MessageFlag::RD());
-    const bool cd = message.getHeaderFlag(MessageFlag::CD());
-    const Opcode& opcode = message.getOpcode();
-    vector<QuestionPtr> questions;
-
-    // If this is an error to a query or notify, we should also copy the
-    // question section.
-    if (opcode == Opcode::QUERY() || opcode == Opcode::NOTIFY()) {
-        questions.assign(message.beginQuestion(), message.endQuestion());
-    }
-
-    message.clear(Message::RENDER);
-    message.setQid(qid);
-    message.setOpcode(opcode);
-    message.setHeaderFlag(MessageFlag::QR());
-    message.setUDPSize(RecursorImpl::DEFAULT_LOCAL_UDPSIZE);
-    if (rd) {
-        message.setHeaderFlag(MessageFlag::RD());
-    }
-    if (cd) {
-        message.setHeaderFlag(MessageFlag::CD());
-    }
-    for_each(questions.begin(), questions.end(), QuestionInserter(&message));
-    message.setRcode(rcode);
-    message.toWire(renderer);
-
-    if (verbose_mode) {
-        cerr << "[b10-recurse] sending an error response (" <<
-            renderer.getLength() << " bytes):\n" << message.toText() << endl;
-    }
-}
+void
+Recursor::setIOService(asiolink::IOService& ios) {
+    impl_->queryShutdown();
+    impl_->querySetup(ios);
+    io_ = &ios;
 }
 
 void
@@ -227,120 +321,114 @@
 }
 
 void
-Recursor::processMessage(const IOMessage& io_message, Message& message,
-                        MessageRenderer& renderer,
-                        BasicServer* server, bool& complete)
+Recursor::processMessage(const IOMessage& io_message, MessagePtr message,
+                        OutputBufferPtr buffer, IOServer* server)
 {
     InputBuffer request_buffer(io_message.getData(), io_message.getDataSize());
-
     // First, check the header part.  If we fail even for the base header,
     // just drop the message.
     try {
-        message.parseHeader(request_buffer);
+        message->parseHeader(request_buffer);
 
         // Ignore all responses.
-        if (message.getHeaderFlag(MessageFlag::QR())) {
+        if (message->getHeaderFlag(MessageFlag::QR())) {
             if (impl_->verbose_mode_) {
                 cerr << "[b10-recurse] received unexpected response, ignoring"
                      << endl;
             }
-            complete = false;
-            server->resume();
+            server->resume(false);
             return;
         }
     } catch (const Exception& ex) {
         if (impl_->verbose_mode_) {
             cerr << "[b10-recurse] DNS packet exception: " << ex.what() << endl;
         }
-        complete = false;
-        server->resume();
+        server->resume(false);
         return;
     }
 
     // Parse the message.  On failure, return an appropriate error.
     try {
-        message.fromWire(request_buffer);
+        message->fromWire(request_buffer);
     } catch (const DNSProtocolError& error) {
         if (impl_->verbose_mode_) {
             cerr << "[b10-recurse] returning " <<  error.getRcode().toText()
                  << ": " << error.what() << endl;
         }
-        makeErrorMessage(message, renderer, error.getRcode(),
-                         impl_->verbose_mode_);
-        complete = true;
-        server->resume();
+        makeErrorMessage(message, buffer, error.getRcode(),
+                         impl_->verbose_mode_);
+        server->resume(true);
         return;
     } catch (const Exception& ex) {
         if (impl_->verbose_mode_) {
             cerr << "[b10-recurse] returning SERVFAIL: " << ex.what() << endl;
         }
-        makeErrorMessage(message, renderer, Rcode::SERVFAIL(),
-                         impl_->verbose_mode_);
-        complete = true;
-        server->resume();
+        makeErrorMessage(message, buffer, Rcode::SERVFAIL(),
+                         impl_->verbose_mode_);
+        server->resume(true);
         return;
     } // other exceptions will be handled at a higher layer.
 
     if (impl_->verbose_mode_) {
         cerr << "[b10-recurse] received a message:\n"
-             << message.toText() << endl;
+             << message->toText() << endl;
     }
 
     // Perform further protocol-level validation.
-    if (message.getOpcode() == Opcode::NOTIFY()) {
-        makeErrorMessage(message, renderer, Rcode::NOTAUTH(),
-                         impl_->verbose_mode_);
-        complete = true;
-    } else if (message.getOpcode() != Opcode::QUERY()) {
+    bool sendAnswer = true;
+    if (message->getOpcode() == Opcode::NOTIFY()) {
+        makeErrorMessage(message, buffer, Rcode::NOTAUTH(),
+                         impl_->verbose_mode_);
+    } else if (message->getOpcode() != Opcode::QUERY()) {
         if (impl_->verbose_mode_) {
             cerr << "[b10-recurse] unsupported opcode" << endl;
         }
-        makeErrorMessage(message, renderer, Rcode::NOTIMP(),
-                         impl_->verbose_mode_);
-        complete = true;
-    } else if (message.getRRCount(Section::QUESTION()) != 1) {
-        makeErrorMessage(message, renderer, Rcode::FORMERR(),
-                         impl_->verbose_mode_);
-        complete = true;
+        makeErrorMessage(message, buffer, Rcode::NOTIMP(),
+                         impl_->verbose_mode_);
+    } else if (message->getRRCount(Section::QUESTION()) != 1) {
+        makeErrorMessage(message, buffer, Rcode::FORMERR(),
+                         impl_->verbose_mode_);
     } else {
-        ConstQuestionPtr question = *message.beginQuestion();
+        ConstQuestionPtr question = *message->beginQuestion();
         const RRType &qtype = question->getType();
         if (qtype == RRType::AXFR()) {
             if (io_message.getSocket().getProtocol() == IPPROTO_UDP) {
-                makeErrorMessage(message, renderer, Rcode::FORMERR(),
+                makeErrorMessage(message, buffer, Rcode::FORMERR(),
                                  impl_->verbose_mode_);
             } else {
-                makeErrorMessage(message, renderer, Rcode::NOTIMP(),
+                makeErrorMessage(message, buffer, Rcode::NOTIMP(),
                                  impl_->verbose_mode_);
             }
-            complete = true;
         } else if (qtype == RRType::IXFR()) {
-            makeErrorMessage(message, renderer, Rcode::NOTIMP(),
-                         impl_->verbose_mode_);
-            complete = true;
+            makeErrorMessage(message, buffer, Rcode::NOTIMP(),
+                         impl_->verbose_mode_);
         } else {
-            complete = impl_->processNormalQuery(io_message, *question,
-                                                 message, renderer, server);
-        }
-    }
-
-    server->resume();
-}
-
-bool
+            // The IOQuery object will post the "resume" event to the
+            // IOServer when an answer arrives, so we don't have to do it now.
+            sendAnswer = false;
+            impl_->processNormalQuery(io_message, *question, message,
+                                      buffer, server);
+        }
+    }
+
+    if (sendAnswer) {
+        server->resume(true);
+    }
+}
+
+void
 RecursorImpl::processNormalQuery(const IOMessage& io_message,
-                                 const Question& question, Message& message,
-                                 MessageRenderer& renderer,
-                                 BasicServer* server)
+                                 const Question& question, MessagePtr message,
+                                 OutputBufferPtr buffer, IOServer* server)
 {
-    const bool dnssec_ok = message.isDNSSECSupported();
-
-    message.makeResponse();
-    message.setRcode(Rcode::NOERROR());
-    message.setDNSSECSupported(dnssec_ok);
-    message.setUDPSize(RecursorImpl::DEFAULT_LOCAL_UDPSIZE);
-    ioquery_.sendQuery(io_message, question, renderer, server);
-    return (true);
+    const bool dnssec_ok = message->isDNSSECSupported();
+
+    message->makeResponse();
+    message->setHeaderFlag(MessageFlag::RA());
+    message->setRcode(Rcode::NOERROR());
+    message->setDNSSECSupported(dnssec_ok);
+    message->setUDPSize(RecursorImpl::DEFAULT_LOCAL_UDPSIZE);
+    ioquery_->sendQuery(io_message, question, buffer, server);
 }
 
 ConstElementPtr

Modified: branches/trac327/src/bin/recurse/recursor.h
==============================================================================
--- branches/trac327/src/bin/recurse/recursor.h (original)
+++ branches/trac327/src/bin/recurse/recursor.h Sun Oct  3 06:44:36 2010
@@ -27,8 +27,6 @@
 namespace isc {
 namespace dns {
 class InputBuffer;
-class Message;
-class MessageRenderer;
 }
 }
 
@@ -51,25 +49,27 @@
 public:
     /// The constructor.
     ///
-    /// \param use_cache Whether to enable hot spot cache for lookup results.
-    /// \param xfrout_client Communication interface with a separate xfrout
-    /// process.  It's normally a reference to an xfr::XfroutClient object,
-    /// but can refer to a local mock object for testing (or other
-    /// experimental) purposes.
-    Recursor(asiolink::IOService& io_service);
+    /// \param forward The address of the name server to which requests
+    /// should be forwarded.  (In the future, when the server is running
+    /// in forwarding mode, the forward nameserver addresses will be set
+    /// via the config channel instaed.)
+    Recursor(const char& forward);
     ~Recursor();
     //@}
     /// \return \c true if the \message contains a response to be returned;
     /// otherwise \c false.
     void processMessage(const asiolink::IOMessage& io_message,
-                        isc::dns::Message& message,
-                        isc::dns::MessageRenderer& response_renderer,
-                        asiolink::BasicServer* server, bool& complete);
+                        isc::dns::MessagePtr message,
+                        isc::dns::OutputBufferPtr buffer,
+                        asiolink::IOServer* server);
     void setVerbose(bool on);
     bool getVerbose() const;
     isc::data::ConstElementPtr updateConfig(isc::data::ConstElementPtr config);
     isc::config::ModuleCCSession* configSession() const;
     void setConfigSession(isc::config::ModuleCCSession* config_session);
+
+    void setIOService(asiolink::IOService& ios);
+    asiolink::IOService& getIOService() const { return (*io_); }
 
     asiolink::DNSLookup* getDNSLookupProvider() {
         return (dns_lookup_);
@@ -83,6 +83,7 @@
 
 private:
     RecursorImpl* impl_;
+    asiolink::IOService* io_;
     asiolink::IOCallback* checkin_;
     asiolink::DNSLookup* dns_lookup_;
     asiolink::DNSAnswer* dns_answer_;

Modified: branches/trac327/src/bin/recurse/tests/recursor_unittest.cc
==============================================================================
--- branches/trac327/src/bin/recurse/tests/recursor_unittest.cc (original)
+++ branches/trac327/src/bin/recurse/tests/recursor_unittest.cc Sun Oct  3 06:44:36 2010
@@ -95,34 +95,42 @@
     };
 
     // A nonoperative task object to be used in calls to processMessage()
-    class MockTask : public BasicServer {
+    class MockTask : public IOServer {
+    public:
+        MockTask() : done_(false) {}
         void operator()(asio::error_code ec UNUSED_PARAM,
                         size_t length UNUSED_PARAM)
         {}
+        // virtual void doLookup() { return; }
+        virtual void resume(const bool done) { done_ = done; }
+        virtual bool hasAnswer() { return (done_); }
+        virtual int value() { return (0); }
+    private:
+        bool done_;
     };
 
 protected:
     RecursorTest() : ios(*TEST_PORT, true, false, NULL, NULL, NULL),
-                    server(ios),
+                    server(*DEFAULT_REMOTE_ADDRESS),
                     request_message(Message::RENDER),
-                    parse_message(Message::PARSE),
+                    parse_message(new Message(Message::PARSE)),
                     default_qid(0x1035), opcode(Opcode(Opcode::QUERY())),
                     qname("www.example.com"),
                     qclass(RRClass::IN()), qtype(RRType::A()),
                     io_message(NULL), endpoint(NULL), request_obuffer(0),
                     request_renderer(request_obuffer),
-                    response_obuffer(0), response_renderer(response_obuffer)
+                    response_obuffer(new OutputBuffer(0))
     {}
     ~RecursorTest() {
         delete io_message;
         delete endpoint;
     }
     MockSession notify_session;
-    MockTask noOp;
+    MockTask task;
     IOService ios;
     Recursor server;
     Message request_message;
-    Message parse_message;
+    MessagePtr parse_message;
     const qid_t default_qid;
     const Opcode opcode;
     const Name qname;
@@ -133,8 +141,7 @@
     const IOEndpoint* endpoint;
     OutputBuffer request_obuffer;
     MessageRenderer request_renderer;
-    OutputBuffer response_obuffer;
-    MessageRenderer response_renderer;
+    OutputBufferPtr response_obuffer;
     vector<uint8_t> data;
 
     void createDataFromFile(const char* const datafile, int protocol);
@@ -305,13 +312,11 @@
         createDataFromFile("simplequery_fromWire");
         data[2] = ((i << 3) & 0xff);
 
-        parse_message.clear(Message::PARSE);
-        bool done;
+        parse_message->clear(Message::PARSE);
         server.processMessage(*io_message, parse_message,
-                              response_renderer, &noOp,
-                              done);
-        EXPECT_TRUE(done);
-        headerCheck(parse_message, default_qid, Rcode::NOTIMP(), i, QR_FLAG,
+                              response_obuffer, &task);
+        EXPECT_TRUE(task.hasAnswer());
+        headerCheck(*parse_message, default_qid, Rcode::NOTIMP(), i, QR_FLAG,
                     0, 0, 0, 0);
     }
 }
@@ -328,13 +333,12 @@
 // Multiple questions.  Should result in FORMERR.
 TEST_F(RecursorTest, multiQuestion) {
     createDataFromFile("multiquestion_fromWire");
-    bool done;
-    server.processMessage(*io_message, parse_message, response_renderer, &noOp, done);
-    EXPECT_TRUE(done);
-    headerCheck(parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(),
+    server.processMessage(*io_message, parse_message, response_obuffer, &task);
+    EXPECT_TRUE(task.hasAnswer());
+    headerCheck(*parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(),
                 QR_FLAG, 2, 0, 0, 0);
 
-    QuestionIterator qit = parse_message.beginQuestion();
+    QuestionIterator qit = parse_message->beginQuestion();
     EXPECT_EQ(Name("example.com"), (*qit)->getName());
     EXPECT_EQ(RRClass::IN(), (*qit)->getClass());
     EXPECT_EQ(RRType::A(), (*qit)->getType());
@@ -343,16 +347,15 @@
     EXPECT_EQ(RRClass::IN(), (*qit)->getClass());
     EXPECT_EQ(RRType::AAAA(), (*qit)->getType());
     ++qit;
-    EXPECT_TRUE(qit == parse_message.endQuestion());
+    EXPECT_TRUE(qit == parse_message->endQuestion());
 }
 
 // Incoming data doesn't even contain the complete header.  Must be silently
 // dropped.
 TEST_F(RecursorTest, shortMessage) {
     createDataFromFile("shortmessage_fromWire");
-    bool done;
-    server.processMessage(*io_message, parse_message, response_renderer, &noOp, done);
-    EXPECT_FALSE(done);
+    server.processMessage(*io_message, parse_message, response_obuffer, &task);
+    EXPECT_FALSE(task.hasAnswer());
 }
 
 // Response messages.  Must be silently dropped, whether it's a valid response
@@ -360,78 +363,73 @@
 TEST_F(RecursorTest, response) {
     // A valid (although unusual) response
     createDataFromFile("simpleresponse_fromWire");
-    bool done;
-    server.processMessage(*io_message, parse_message, response_renderer, &noOp, done);
-    EXPECT_FALSE(done);
+    server.processMessage(*io_message, parse_message, response_obuffer, &task);
+    EXPECT_FALSE(task.hasAnswer());
 
     // A response with a broken question section.  must be dropped rather than
     // returning FORMERR.
     createDataFromFile("shortresponse_fromWire");
-    server.processMessage(*io_message, parse_message, response_renderer, &noOp, done);
-    EXPECT_FALSE(done);
+    server.processMessage(*io_message, parse_message, response_obuffer, &task);
+    EXPECT_FALSE(task.hasAnswer());
 
     // A response to iquery.  must be dropped rather than returning NOTIMP.
     createDataFromFile("iqueryresponse_fromWire");
-    server.processMessage(*io_message, parse_message, response_renderer, &noOp, done);
-    EXPECT_FALSE(done);
+    server.processMessage(*io_message, parse_message, response_obuffer, &task);
+    EXPECT_FALSE(task.hasAnswer());
 }
 
 // Query with a broken question
 TEST_F(RecursorTest, shortQuestion) {
     createDataFromFile("shortquestion_fromWire");
-    bool done;
-    server.processMessage(*io_message, parse_message, response_renderer, &noOp, done);
-    EXPECT_TRUE(done);
+    server.processMessage(*io_message, parse_message, response_obuffer, &task);
+    EXPECT_TRUE(task.hasAnswer());
     // Since the query's question is broken, the question section of the
     // response should be empty.
-    headerCheck(parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(),
+    headerCheck(*parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(),
                 QR_FLAG, 0, 0, 0, 0);
 }
 
 // Query with a broken answer section
 TEST_F(RecursorTest, shortAnswer) {
     createDataFromFile("shortanswer_fromWire");
-    bool done;
-    server.processMessage(*io_message, parse_message, response_renderer, &noOp, done);
-    EXPECT_TRUE(done);
+    server.processMessage(*io_message, parse_message, response_obuffer, &task);
+    EXPECT_TRUE(task.hasAnswer());
 
     // This is a bogus query, but question section is valid.  So the response
     // should copy the question section.
-    headerCheck(parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(),
+    headerCheck(*parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(),
                 QR_FLAG, 1, 0, 0, 0);
 
-    QuestionIterator qit = parse_message.beginQuestion();
+    QuestionIterator qit = parse_message->beginQuestion();
     EXPECT_EQ(Name("example.com"), (*qit)->getName());
     EXPECT_EQ(RRClass::IN(), (*qit)->getClass());
     EXPECT_EQ(RRType::A(), (*qit)->getType());
     ++qit;
-    EXPECT_TRUE(qit == parse_message.endQuestion());
+    EXPECT_TRUE(qit == parse_message->endQuestion());
 }
 
 // Query with unsupported version of EDNS.
 TEST_F(RecursorTest, ednsBadVers) {
     createDataFromFile("queryBadEDNS_fromWire");
-    bool done;
-    server.processMessage(*io_message, parse_message, response_renderer, &noOp, done);
-    EXPECT_TRUE(done);
+    server.processMessage(*io_message, parse_message, response_obuffer, &task);
+    EXPECT_TRUE(task.hasAnswer());
 
     // The response must have an EDNS OPT RR in the additional section.
     // Note that the DNSSEC DO bit is cleared even if this bit in the query
     // is set.  This is a limitation of the current implementation.
-    headerCheck(parse_message, default_qid, Rcode::BADVERS(), opcode.getCode(),
+    headerCheck(*parse_message, default_qid, Rcode::BADVERS(), opcode.getCode(),
                 QR_FLAG, 1, 0, 0, 1);
-    EXPECT_EQ(4096, parse_message.getUDPSize());
-    EXPECT_FALSE(parse_message.isDNSSECSupported());
+    EXPECT_EQ(4096, parse_message->getUDPSize());
+    EXPECT_FALSE(parse_message->isDNSSECSupported());
 }
 
 TEST_F(RecursorTest, AXFROverUDP) {
     // AXFR over UDP is invalid and should result in FORMERR.
     createRequestPacket(opcode, Name("example.com"), RRClass::IN(),
                         RRType::AXFR(), IPPROTO_UDP);
-    bool done;
-    server.processMessage(*io_message, parse_message, response_renderer, &noOp, done);
-    EXPECT_TRUE(done);
-    headerCheck(parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(),
+    server.processMessage(*io_message, parse_message, response_obuffer, &task);
+    EXPECT_TRUE(task.hasAnswer());
+    headerCheck(*parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(),
                 QR_FLAG, 1, 0, 0, 0);
 }
 
@@ -439,10 +437,9 @@
     createRequestPacket(opcode, Name("example.com"), RRClass::IN(),
                         RRType::AXFR(), IPPROTO_TCP);
     // AXFR is not implemented and should always send NOTIMP.
-    bool done;
-    server.processMessage(*io_message, parse_message, response_renderer, &noOp, done);
-    EXPECT_TRUE(done);
-    headerCheck(parse_message, default_qid, Rcode::NOTIMP(), opcode.getCode(),
+    server.processMessage(*io_message, parse_message, response_obuffer, &task);
+    EXPECT_TRUE(task.hasAnswer());
+    headerCheck(*parse_message, default_qid, Rcode::NOTIMP(), opcode.getCode(),
                 QR_FLAG, 1, 0, 0, 0);
 }
 
@@ -454,10 +451,9 @@
     request_message.setQid(default_qid);
     request_message.toWire(request_renderer);
     createRequestPacket(IPPROTO_UDP);
-    bool done;
-    server.processMessage(*io_message, parse_message, response_renderer, &noOp, done);
-    EXPECT_TRUE(done);
-    headerCheck(parse_message, default_qid, Rcode::NOTAUTH(),
+    server.processMessage(*io_message, parse_message, response_obuffer, &task);
+    EXPECT_TRUE(task.hasAnswer());
+    headerCheck(*parse_message, default_qid, Rcode::NOTAUTH(),
                 Opcode::NOTIFY().getCode(), QR_FLAG, 0, 0, 0, 0);
 }
 

Modified: branches/trac327/src/lib/asiolink/asiolink.cc
==============================================================================
--- branches/trac327/src/lib/asiolink/asiolink.cc (original)
+++ branches/trac327/src/lib/asiolink/asiolink.cc Sun Oct  3 06:44:36 2010
@@ -28,7 +28,6 @@
 
 #include <dns/buffer.h>
 #include <dns/message.h>
-#include <dns/messagerenderer.h>
 
 #include <asiolink/asiolink.h>
 #include <asiolink/internal/tcpdns.h>
@@ -94,24 +93,30 @@
     remote_endpoint_(remote_endpoint)
 {}
 
-IOQuery::IOQuery(IOService& io_service) : io_service_(io_service) {}
+IOQuery::IOQuery(IOService& io_service, const char& forward) :
+    io_service_(io_service)
+{
+    error_code err;
+    ns_addr_ = ip::address::from_string(&forward, err);
+    if (err) {
+        isc_throw(IOError, "Invalid IP address '" << &ns_addr_ << "': "
+                  << err.message());
+    }
+}
 
 void
 IOQuery::sendQuery(const IOMessage& io_message,
-                   const Question& question, MessageRenderer& renderer,
-                   BasicServer* completer)
-{
-    error_code err;
-    // XXX: hard-code the address for now:
-    const ip::address addr = ip::address::from_string("192.168.1.12", err);
+                   const Question& question, OutputBufferPtr buffer,
+                   IOServer* server)
+{
 
     // XXX: eventually we will need to be able to determine whether
     // the message should be sent via TCP or UDP, or sent initially via
     // UDP and then fall back to TCP on failure, but for the moment
     // we're only going to handle UDP.
-    UDPQuery* query = new UDPQuery(io_service_.get_io_service(), io_message,
-                                   question, addr, renderer, completer);
-    (*query)();
+    asio::io_service& io = io_service_.get_io_service();
+    UDPQuery q(io, io_message, question, ns_addr_, buffer, server);
+    io.post(q);
 }
 
 class IOServiceImpl {

Modified: branches/trac327/src/lib/asiolink/asiolink.h
==============================================================================
--- branches/trac327/src/lib/asiolink/asiolink.h (original)
+++ branches/trac327/src/lib/asiolink/asiolink.h Sun Oct  3 06:44:36 2010
@@ -28,6 +28,7 @@
 
 #include <boost/function.hpp>
 
+#include <dns/buffer.h>
 #include <dns/message.h>
 #include <dns/messagerenderer.h>
 #include <dns/question.h>
@@ -388,19 +389,29 @@
 };
 
 /// XXX: need to add doc
-class BasicServer {
-public:
-    BasicServer() : self(this) {}
+class IOServer;
+typedef boost::shared_ptr<IOServer> IOServerPtr;
+class IOServer {
+public:
+    IOServer() : self_(this), cloned_(false) {}
+
     virtual void operator()(asio::error_code ec = asio::error_code(),
                             size_t length = 0)
     {
-        (*self)(ec, length);
+        (*self_)(ec, length);
     }
 
-    virtual void doLookup() {}
-    virtual void resume() {}
-private:
-    BasicServer* self;
+    virtual void doLookup() { self_->doLookup(); }
+    virtual void resume(const bool done) { self_->resume(done); }
+    virtual bool hasAnswer() { return (self_->hasAnswer()); }
+    virtual int value() { return (self_->value()); }
+    virtual IOServer* clone() { return (self_->clone()); }
+
+private:
+    IOServer* self_;
+
+protected:
+    bool cloned_;
 };
 
 template <typename T>
@@ -437,7 +448,7 @@
     ///
     /// This is intentionally defined as \c protected as this base class
     /// should never be instantiated (except as part of a derived class).
-    DNSLookup() : self(this) {}
+    DNSLookup() : self_(this) {}
 public:
     /// \brief The destructor
     virtual ~DNSLookup() {}
@@ -447,16 +458,15 @@
     /// that the function ultimately invoked will be the one in the derived
     /// class.
     virtual void operator()(const IOMessage& io_message,
-                            isc::dns::Message& dns_message,
-                            isc::dns::MessageRenderer& renderer,
-                            BasicServer* server, bool& success)
-                            const
+                            isc::dns::MessagePtr message,
+                            isc::dns::OutputBufferPtr buffer,
+                            IOServer* server) const
     {
-        (*self)(io_message, dns_message, renderer, server, success);
+        (*self_)(io_message, message, buffer, server);
     }
     //@}
 private:
-    DNSLookup* self;
+    DNSLookup* self_;
 };
 
 /// \brief The \c DNSAnswer class is an abstract base class for a DNS
@@ -488,8 +498,8 @@
     virtual ~DNSAnswer() {}
     /// \brief The function operator
     virtual void operator()(const IOMessage& io_message,
-                            isc::dns::Message& dns_message,
-                            isc::dns::MessageRenderer& renderer) const = 0;
+                            isc::dns::MessagePtr message,
+                            isc::dns::OutputBufferPtr buffer) const = 0;
     //@}
 };
 
@@ -516,7 +526,7 @@
     ///
     /// This is intentionally defined as \c protected as this base class
     /// should never be instantiated (except as part of a derived class).
-    IOCallback() : self(this) {}
+    IOCallback() : self_(this) {}
 public:
     /// \brief The destructor
     virtual ~IOCallback() {}
@@ -526,11 +536,11 @@
     /// that the function ultimately invoked will be the one in the derived
     /// class.
     virtual void operator()(const IOMessage& io_message) const {
-        (*self)(io_message);
+        (*self_)(io_message);
     }
     //@}
 private:
-    IOCallback* self;
+    IOCallback* self_;
 };
 
 /// \brief The \c IOService class is a wrapper for the ASIO \c io_service
@@ -600,13 +610,16 @@
 /// the ASIO code that carries out upstream queries.
 class IOQuery {
 public:
-    IOQuery(IOService& io_service);
+    IOQuery(IOService& io_service, const char& forward);
+
+    /// \brief Sends a query to the IOQuery object.
     void sendQuery(const IOMessage& io_message,
                    const isc::dns::Question& question,
-                   isc::dns::MessageRenderer& renderer,
-                   BasicServer* caller);
+                   isc::dns::OutputBufferPtr buffer,
+                   IOServer* server);
 private:
     IOService& io_service_;
+    asio::ip::address ns_addr_;
 };
 
 }      // asiolink

Modified: branches/trac327/src/lib/asiolink/internal/tcpdns.h
==============================================================================
--- branches/trac327/src/lib/asiolink/internal/tcpdns.h (original)
+++ branches/trac327/src/lib/asiolink/internal/tcpdns.h Sun Oct  3 06:44:36 2010
@@ -25,7 +25,6 @@
 
 #include <dns/buffer.h>
 #include <dns/message.h>
-#include <dns/messagerenderer.h>
 
 #include <asiolink/asiolink.h>
 #include <asiolink/internal/coroutine.h>
@@ -73,7 +72,7 @@
 //
 // Asynchronous TCP server coroutine
 //
-class TCPServer : public virtual BasicServer, public virtual coroutine {
+class TCPServer : public virtual IOServer, public virtual coroutine {
 public:
     explicit TCPServer(asio::io_service& io_service,
                        const asio::ip::address& addr, const uint16_t port, 
@@ -85,7 +84,15 @@
                     size_t length = 0);
 
     void doLookup();
-    void resume();
+    void resume(const bool done);
+    bool hasAnswer() { return (done_); }
+    int value() { return (get_value()); }
+
+    IOServer* clone() {
+        TCPServer* s = new TCPServer(*this);
+        s->cloned_ = true;
+        return (s);
+    }
 
 private:
     enum { MAX_LENGTH = 65535 };
@@ -100,12 +107,12 @@
     // constructor or in the coroutine.
     boost::shared_ptr<asio::ip::tcp::acceptor> acceptor_;
     boost::shared_ptr<asio::ip::tcp::socket> socket_;
-    boost::shared_ptr<isc::dns::MessageRenderer> renderer_;
     boost::shared_ptr<isc::dns::OutputBuffer> lenbuf_;
     boost::shared_ptr<isc::dns::OutputBuffer> respbuf_;
     boost::shared_ptr<asiolink::IOEndpoint> peer_;
     boost::shared_ptr<asiolink::IOSocket> iosock_;
     boost::shared_ptr<asiolink::IOMessage> io_message_;
+    isc::dns::MessagePtr message_;
     boost::shared_ptr<char> data_;
 
     // State information that is entirely internal to a given instance

Modified: branches/trac327/src/lib/asiolink/internal/udpdns.h
==============================================================================
--- branches/trac327/src/lib/asiolink/internal/udpdns.h (original)
+++ branches/trac327/src/lib/asiolink/internal/udpdns.h Sun Oct  3 06:44:36 2010
@@ -20,6 +20,7 @@
 #include <config.h>
 
 #include <asio.hpp>
+#include <boost/shared_array.hpp>
 #include <boost/shared_ptr.hpp>
 
 #include <dns/buffer.h>
@@ -72,7 +73,7 @@
 //
 // Asynchronous UDP server coroutine
 //
-class UDPServer : public virtual BasicServer, public virtual coroutine {
+class UDPServer : public virtual IOServer, public virtual coroutine {
 public:
     explicit UDPServer(asio::io_service& io_service,
                        const asio::ip::address& addr, const uint16_t port,
@@ -84,11 +85,18 @@
                     size_t length = 0);
 
     enum { MAX_LENGTH = 4096 };
-    char answer[MAX_LENGTH];
     asio::ip::udp::endpoint peer;
 
     void doLookup();
-    void resume();
+    void resume(const bool done);
+    bool hasAnswer() { return (done_); }
+    int value() { return (get_value()); }
+
+    IOServer* clone() {
+        UDPServer* s = new UDPServer(*this);
+        s->cloned_ = true;
+        return (s);
+    }
 
 private:
     asio::io_service& io_;
@@ -101,15 +109,14 @@
     boost::shared_ptr<asio::ip::udp::socket> socket_;
     boost::shared_ptr<char> data_;
     boost::shared_ptr<asio::ip::udp::endpoint> sender_;
-    boost::shared_ptr<isc::dns::MessageRenderer> renderer_;
-    boost::shared_ptr<isc::dns::Message> message_;
     boost::shared_ptr<asiolink::IOEndpoint> peer_;
     boost::shared_ptr<asiolink::IOSocket> iosock_;
     boost::shared_ptr<asiolink::IOMessage> io_message_;
+    isc::dns::MessagePtr message_;
+    isc::dns::OutputBufferPtr respbuf_;
 
     // State information that is entirely internal to a given instance
     // of the coroutine can be declared here.
-    isc::dns::OutputBuffer respbuf_;
     size_t bytes_;
     bool done_;
 
@@ -128,20 +135,26 @@
                       const IOMessage& io_message,
                       const isc::dns::Question& q,
                       const asio::ip::address& addr,
-                      isc::dns::MessageRenderer& renderer,
-                      BasicServer* caller);
+                      isc::dns::OutputBufferPtr buffer,
+                      IOServer* server);
     void operator()(asio::error_code ec = asio::error_code(),
                     size_t length = 0); 
 private:
+    enum { MAX_LENGTH = 4096 };
+
     boost::shared_ptr<asio::ip::udp::socket> socket_;
-    asio::ip::udp::endpoint server_;
+    asio::ip::udp::endpoint remote_;
     isc::dns::Question question_;
-    char* data_;
-    size_t datalen_;
     isc::dns::OutputBuffer msgbuf_;
-    BasicServer* caller_;
+    isc::dns::OutputBufferPtr buffer_;;
+    boost::shared_array<char> data_;
+
+    /// \brief The UDP or TCP Server object from which the query originated.
+    // IOServerPtr server_;
+    IOServer* server_;
 };
 }
+
 
 #endif // __UDPDNS_H
 

Modified: branches/trac327/src/lib/asiolink/tcpdns.cc
==============================================================================
--- branches/trac327/src/lib/asiolink/tcpdns.cc (original)
+++ branches/trac327/src/lib/asiolink/tcpdns.cc Sun Oct  3 06:44:36 2010
@@ -29,7 +29,6 @@
 
 #include <dns/buffer.h>
 #include <dns/message.h>
-#include <dns/messagerenderer.h>
 
 #include <asiolink.h>
 #include <internal/coroutine.h>
@@ -153,7 +152,7 @@
         // Reset or instantiate objects that will be needed by the
         // DNS lookup and the write call.
         respbuf_->clear();
-        renderer_.reset(new MessageRenderer(*respbuf_));
+        message_.reset(new Message(Message::PARSE));
 
         // Process the DNS message.
         bytes_ = length;
@@ -162,6 +161,8 @@
         if (!done_) {
             CORO_YIELD return;
         }
+
+        (*answer_callback_)(*io_message_, message_, respbuf_);
 
         // Send the response.
         lenbuf_->clear();
@@ -174,12 +175,12 @@
 
 void
 TCPServer::doLookup() {
-    Message message(Message::PARSE);
-    (*lookup_callback_)(*io_message_, message, *renderer_, this, done_);
+    (*lookup_callback_)(*io_message_, message_, respbuf_, this);
 }
 
 void
-TCPServer::resume() {
+TCPServer::resume(const bool done) {
+    done_ = done;
     io_.post(*this);
 }
 

Modified: branches/trac327/src/lib/asiolink/udpdns.cc
==============================================================================
--- branches/trac327/src/lib/asiolink/udpdns.cc (original)
+++ branches/trac327/src/lib/asiolink/udpdns.cc Sun Oct  3 06:44:36 2010
@@ -80,7 +80,7 @@
                      IOCallback* checkin,
                      DNSLookup* lookup,
                      DNSAnswer* answer) :
-    io_(io_service), respbuf_(0), done_(false),
+    io_(io_service), done_(false),
     checkin_callback_(checkin), lookup_callback_(lookup),
     answer_callback_(answer)
 {
@@ -135,8 +135,7 @@
 
         // Instantiate objects that will be needed by the
         // asynchronous send call.
-        respbuf_.clear();
-        renderer_.reset(new MessageRenderer(respbuf_));
+        respbuf_.reset(new OutputBuffer(0));
         message_.reset(new Message(Message::PARSE));
 
         CORO_YIELD io_.post(LookupHandler<UDPServer>(*this));
@@ -145,33 +144,32 @@
             CORO_YIELD return;
         }
 
-        (*answer_callback_)(*io_message_, *message_, *renderer_);
-        CORO_YIELD socket_->async_send_to(buffer(respbuf_.getData(),
-                                                 respbuf_.getLength()),
+        (*answer_callback_)(*io_message_, message_, respbuf_);
+        CORO_YIELD socket_->async_send_to(buffer(respbuf_->getData(),
+                                                 respbuf_->getLength()),
                                      *sender_, *this);
     }
 }
 
 void
 UDPServer::doLookup() {
-    (*lookup_callback_)(*io_message_, *message_, *renderer_, this, done_);
-}
-
-void
-UDPServer::resume() {
+    (*lookup_callback_)(*io_message_, message_, respbuf_, this);
+}
+
+void
+UDPServer::resume(const bool done) {
+    done_ = done;
     io_.post(*this);
 }
 
 UDPQuery::UDPQuery(io_service& io_service, const IOMessage& io_message,
                    const Question& q, const ip::address& addr,
-                   MessageRenderer& renderer, BasicServer* caller) :
-    question_(q),
-    data_((char*) renderer.getData()), datalen_(renderer.getLength()),
-    msgbuf_(512), caller_(caller)
+                   OutputBufferPtr buffer, IOServer* server) :
+    question_(q), msgbuf_(512), buffer_(buffer), server_(server->clone())
 {
     udp proto = addr.is_v4() ? udp::v4() : udp::v6();
     socket_.reset(new udp::socket(io_service, proto));
-    server_ = udp::endpoint(addr, 53);
+    remote_ = udp::endpoint(addr, 53);
 }
 
 void
@@ -194,13 +192,16 @@
 
         CORO_YIELD socket_->async_send_to(buffer(msgbuf_.getData(),
                                                  msgbuf_.getLength()),
-                                           server_, *this);
-
-        CORO_YIELD socket_->async_receive_from(buffer(data_, datalen_),
-                                               server_, *this);
-    }
-
-    caller_->resume();
-}
-
-}
+                                           remote_, *this);
+
+        data_.reset(new char[MAX_LENGTH]);
+        CORO_YIELD socket_->async_receive_from(buffer(data_.get(), MAX_LENGTH),
+                                               remote_, *this);
+
+        buffer_->writeData(data_.get(), length);
+        server_->resume(true);
+    }
+
+}
+
+}

Modified: branches/trac327/src/lib/dns/buffer.h
==============================================================================
--- branches/trac327/src/lib/dns/buffer.h (original)
+++ branches/trac327/src/lib/dns/buffer.h Sun Oct  3 06:44:36 2010
@@ -25,6 +25,8 @@
 
 #include <exceptions/exceptions.h>
 
+#include <boost/shared_ptr.hpp>
+
 namespace isc {
 namespace dns {
 
@@ -412,6 +414,16 @@
 private:
     std::vector<uint8_t> data_;
 };
+
+/// \brief Pointer-like types pointing to \c InputBuffer or \c OutputBuffer
+///
+/// These types are expected to be used as an argument in asynchronous
+/// callback functions.  The internal reference-counting will ensure that
+/// that ongoing state information will not be lost if the object
+/// that originated the asynchronous call falls out of scope.
+typedef boost::shared_ptr<InputBuffer> InputBufferPtr;
+typedef boost::shared_ptr<OutputBuffer> OutputBufferPtr;
+
 }
 }
 #endif  // __BUFFER_H

Modified: branches/trac327/src/lib/dns/message.h
==============================================================================
--- branches/trac327/src/lib/dns/message.h (original)
+++ branches/trac327/src/lib/dns/message.h Sun Oct  3 06:44:36 2010
@@ -798,6 +798,14 @@
     MessageImpl* impl_;
 };
 
+/// \brief Pointer-like type pointing to a \c Message
+///
+/// This type is expected to be used as an argument in asynchronous
+/// callback functions.  The internal reference-counting will ensure that
+/// that ongoing state information will not be lost if the object
+/// that originated the asynchronous call falls out of scope.
+typedef boost::shared_ptr<Message> MessagePtr;
+
 std::ostream& operator<<(std::ostream& os, const Opcode& opcode);
 std::ostream& operator<<(std::ostream& os, const Rcode& rcode);
 std::ostream& operator<<(std::ostream& os, const Message& message);

Modified: branches/trac327/src/lib/dns/messagerenderer.h
==============================================================================
--- branches/trac327/src/lib/dns/messagerenderer.h (original)
+++ branches/trac327/src/lib/dns/messagerenderer.h Sun Oct  3 06:44:36 2010
@@ -258,6 +258,7 @@
     /// \param name A \c Name object to be written.
     /// \param compress A boolean indicating whether to enable name compression.
     void writeName(const Name& name, bool compress = true);
+    //@}
 private:
     struct MessageRendererImpl;
     MessageRendererImpl* impl_;




More information about the bind10-changes mailing list