Browse Source

[master] Merge branch 'master' of ssh://git.bind10.isc.org/var/bind10/git/bind10

Jelte Jansen 13 years ago
parent
commit
3b53272a6f

+ 5 - 0
ChangeLog

@@ -1,3 +1,8 @@
+387.	[build]		muks
+	Accept a --without-werror configure switch so that some builders can
+	disable the use of -Werror in CFLAGS when building.
+	(Trac #1671, git 8684a411d7718a71ad9fb616f56b26436c4f03e5)
+
 386.	[bug]		jelte
 386.	[bug]		jelte
 	Upon initial sqlite3 database creation, the 'diffs' table is now
 	Upon initial sqlite3 database creation, the 'diffs' table is now
 	always created. This already happened most of the time, but there
 	always created. This already happened most of the time, but there

+ 21 - 8
configure.ac

@@ -288,8 +288,6 @@ AC_DEFUN([BIND10_CXX_TRY_FLAG], [
   AC_MSG_RESULT([$bind10_cxx_flag])
   AC_MSG_RESULT([$bind10_cxx_flag])
 ])
 ])
 
 
-werror_ok=0
-
 # SunStudio compiler requires special compiler options for boost
 # SunStudio compiler requires special compiler options for boost
 # (http://blogs.sun.com/sga/entry/boost_mini_howto)
 # (http://blogs.sun.com/sga/entry/boost_mini_howto)
 if test "$SUNCXX" = "yes"; then
 if test "$SUNCXX" = "yes"; then
@@ -315,19 +313,34 @@ case "$host" in
 	;;
 	;;
 esac
 esac
 
 
+# Don't use -Werror if configured not to
+AC_ARG_WITH(werror,
+    AC_HELP_STRING([--with-werror], [Compile using -Werror (default=yes)]),
+    [
+     case "${withval}" in
+         yes) with_werror=1 ;;
+         no)  with_werror=0 ;;
+         *)   AC_MSG_ERROR(bad value ${withval} for --with-werror) ;;
+     esac],
+     [with_werror=1])
+
+werror_ok=0
+
 # Certain versions of gcc (g++) have a bug that incorrectly warns about
 # Certain versions of gcc (g++) have a bug that incorrectly warns about
 # the use of anonymous name spaces even if they're closed in a single
 # the use of anonymous name spaces even if they're closed in a single
 # translation unit.  For these versions we have to disable -Werror.
 # translation unit.  For these versions we have to disable -Werror.
-CXXFLAGS_SAVED="$CXXFLAGS"
-CXXFLAGS="$CXXFLAGS $B10_CXXFLAGS -Werror"
-AC_MSG_CHECKING(for in-TU anonymous namespace breakage)
-AC_TRY_COMPILE([namespace { class Foo {}; }
-namespace isc {class Bar {Foo foo_;};} ],,
+if test $with_werror = 1; then
+   CXXFLAGS_SAVED="$CXXFLAGS"
+   CXXFLAGS="$CXXFLAGS $B10_CXXFLAGS -Werror"
+   AC_MSG_CHECKING(for in-TU anonymous namespace breakage)
+   AC_TRY_COMPILE([namespace { class Foo {}; }
+   namespace isc {class Bar {Foo foo_;};} ],,
 	[AC_MSG_RESULT(no)
 	[AC_MSG_RESULT(no)
 	 werror_ok=1
 	 werror_ok=1
 	 B10_CXXFLAGS="$B10_CXXFLAGS -Werror"],
 	 B10_CXXFLAGS="$B10_CXXFLAGS -Werror"],
 	[AC_MSG_RESULT(yes)])
 	[AC_MSG_RESULT(yes)])
-CXXFLAGS="$CXXFLAGS_SAVED"
+   CXXFLAGS="$CXXFLAGS_SAVED"
+fi
 
 
 # Python 3.2 has an unused parameter in one of its headers. This
 # Python 3.2 has an unused parameter in one of its headers. This
 # has been reported, but not fixed as of yet, so we check if we need
 # has been reported, but not fixed as of yet, so we check if we need

+ 1 - 0
src/lib/asiodns/Makefile.am

@@ -24,6 +24,7 @@ libasiodns_la_SOURCES += dns_server.h
 libasiodns_la_SOURCES += dns_service.cc dns_service.h
 libasiodns_la_SOURCES += dns_service.cc dns_service.h
 libasiodns_la_SOURCES += tcp_server.cc tcp_server.h
 libasiodns_la_SOURCES += tcp_server.cc tcp_server.h
 libasiodns_la_SOURCES += udp_server.cc udp_server.h
 libasiodns_la_SOURCES += udp_server.cc udp_server.h
+libasiodns_la_SOURCES += sync_udp_server.cc sync_udp_server.h
 libasiodns_la_SOURCES += io_fetch.cc io_fetch.h
 libasiodns_la_SOURCES += io_fetch.cc io_fetch.h
 libasiodns_la_SOURCES += logger.h logger.cc
 libasiodns_la_SOURCES += logger.h logger.cc
 
 

+ 0 - 16
src/lib/asiodns/dns_server.h

@@ -88,22 +88,6 @@ public:
     ///             to return.
     ///             to return.
     virtual void resume(const bool done) { self_->resume(done); }
     virtual void resume(const bool done) { self_->resume(done); }
 
 
-    /// \brief Indicate whether the server is able to send an answer
-    /// to a query.
-    ///
-    /// This is presently used only for testing purposes.
-    virtual bool hasAnswer() { return (self_->hasAnswer()); }
-
-    /// \brief Returns the current value of the 'coroutine' object
-    ///
-    /// This is a temporary method, intended to be used for debugging
-    /// purposes during development and removed later.  It allows
-    /// callers from outside the coroutine object to retrieve information
-    /// about its current state.
-    ///
-    /// \return The value of the 'coroutine' object
-    virtual int value() { return (self_->value()); }
-
     /// \brief Returns a pointer to a clone of this DNSServer object.
     /// \brief Returns a pointer to a clone of this DNSServer object.
     ///
     ///
     /// When a \c DNSServer object is copied or assigned, the result will
     /// When a \c DNSServer object is copied or assigned, the result will

+ 216 - 0
src/lib/asiodns/sync_udp_server.cc

@@ -0,0 +1,216 @@
+// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+
+#include <asio.hpp>
+#include <asio/error.hpp>
+
+#include "sync_udp_server.h"
+#include "logger.h"
+
+#include <asiolink/dummy_io_cb.h>
+#include <asiolink/udp_endpoint.h>
+#include <asiolink/udp_socket.h>
+
+#include <boost/bind.hpp>
+
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <unistd.h>             // for some IPC/network system calls
+#include <errno.h>
+
+using namespace std;
+using namespace boost;
+using namespace isc::asiolink;
+
+namespace isc {
+namespace asiodns {
+
+SyncUDPServer::SyncUDPServer(asio::io_service& io_service,
+                             const asio::ip::address& addr,
+                             const uint16_t port,
+                             asiolink::SimpleCallback* checkin,
+                             DNSLookup* lookup, DNSAnswer* answer) :
+    output_buffer_(new isc::util::OutputBuffer(0)),
+    query_(new isc::dns::Message(isc::dns::Message::PARSE)),
+    answer_(new isc::dns::Message(isc::dns::Message::RENDER)),
+    io_(io_service), checkin_callback_(checkin), lookup_callback_(lookup),
+    answer_callback_(answer), stopped_(false)
+{
+    // We must use different instantiations for v4 and v6;
+    // otherwise ASIO will bind to both
+    asio::ip::udp proto = addr.is_v4() ? asio::ip::udp::v4() :
+        asio::ip::udp::v6();
+    socket_.reset(new asio::ip::udp::socket(io_service, proto));
+    socket_->set_option(asio::socket_base::reuse_address(true));
+    if (addr.is_v6()) {
+        socket_->set_option(asio::ip::v6_only(true));
+    }
+    socket_->bind(asio::ip::udp::endpoint(addr, port));
+}
+
+SyncUDPServer::SyncUDPServer(asio::io_service& io_service, const int fd,
+                             const int af, asiolink::SimpleCallback* checkin,
+                             DNSLookup* lookup, DNSAnswer* answer) :
+    output_buffer_(new isc::util::OutputBuffer(0)),
+    query_(new isc::dns::Message(isc::dns::Message::PARSE)),
+    answer_(new isc::dns::Message(isc::dns::Message::RENDER)),
+    io_(io_service), checkin_callback_(checkin), lookup_callback_(lookup),
+    answer_callback_(answer), stopped_(false)
+{
+    if (af != AF_INET && af != AF_INET6) {
+        isc_throw(InvalidParameter, "Address family must be either AF_INET "
+                  "or AF_INET6, not " << af);
+    }
+    LOG_DEBUG(logger, DBGLVL_TRACE_BASIC, ASIODNS_FD_ADD_UDP).arg(fd);
+    try {
+        socket_.reset(new asio::ip::udp::socket(io_service));
+        socket_->assign(af == AF_INET6 ? asio::ip::udp::v6() :
+                        asio::ip::udp::v4(), fd);
+    } catch (const std::exception& exception) {
+        // Whatever the thing throws, it is something from ASIO and we
+        // convert it
+        isc_throw(IOError, exception.what());
+    }
+}
+
+void
+SyncUDPServer::scheduleRead() {
+    socket_->async_receive_from(asio::buffer(data_, MAX_LENGTH), sender_,
+                                boost::bind(&SyncUDPServer::handleRead, this,
+                                            _1, _2));
+}
+
+void
+SyncUDPServer::handleRead(const asio::error_code& ec, const size_t length) {
+    // Abort on fatal errors
+    if (ec) {
+        using namespace asio::error;
+        if (ec.value() != would_block && ec.value() != try_again &&
+            ec.value() != interrupted) {
+            return;
+        }
+    }
+    // Some kind of interrupt, spurious wakeup, or like that. Just try reading
+    // again.
+    if (ec || length == 0) {
+        scheduleRead();
+        return;
+    }
+    // OK, we have a real packet of data. Let's dig into it!
+
+    // XXX: This is taken (and ported) from UDPSocket class. What the hell does
+    // it really mean?
+
+    // The UDP socket class has been extended with asynchronous functions
+    // and takes as a template parameter a completion callback class.  As
+    // UDPServer does not use these extended functions (only those defined
+    // in the IOSocket base class) - but needs a UDPSocket to get hold of
+    // the underlying Boost UDP socket - DummyIOCallback is used.  This
+    // provides the appropriate operator() but is otherwise functionless.
+    UDPSocket<DummyIOCallback> socket(*socket_);
+    UDPEndpoint endpoint(sender_);
+    IOMessage message(data_, length, socket, endpoint);
+    if (checkin_callback_ != NULL) {
+        (*checkin_callback_)(message);
+        if (stopped_) {
+            return;
+        }
+    }
+
+    // If we don't have a DNS Lookup provider, there's no point in
+    // continuing; we exit the coroutine permanently.
+    if (lookup_callback_ == NULL) {
+        scheduleRead();
+        return;
+    }
+
+    // Make sure the buffers are fresh
+    output_buffer_->clear();
+    query_->clear(isc::dns::Message::PARSE);
+    answer_->clear(isc::dns::Message::RENDER);
+
+    // Mark that we don't have an answer yet.
+    done_ = false;
+    resume_called_ = false;
+
+    // Call the actual lookup
+    (*lookup_callback_)(message, query_, answer_, output_buffer_, this);
+
+    if (!resume_called_) {
+        isc_throw(isc::Unexpected,
+                  "No resume called from the lookup callback");
+    }
+
+    if (stopped_) {
+        return;
+    }
+
+    if (done_) {
+        // Good, there's an answer.
+        // Call the answer callback to render it.
+        (*answer_callback_)(message, query_, answer_, output_buffer_);
+
+        if (stopped_) {
+            return;
+        }
+
+        socket_->send_to(asio::buffer(output_buffer_->getData(),
+                                      output_buffer_->getLength()),
+                         sender_);
+    }
+
+    // And schedule handling another socket.
+    scheduleRead();
+}
+
+void
+SyncUDPServer::operator()(asio::error_code, size_t) {
+    // To start the server, we just schedule reading of data when they
+    // arrive.
+    scheduleRead();
+}
+
+/// Stop the UDPServer
+void
+SyncUDPServer::stop() {
+    /// Using close instead of cancel, because cancel
+    /// will only cancel the asynchornized event already submitted
+    /// to io service, the events post to io service after
+    /// cancel still can be scheduled by io service, if
+    /// the socket is cloesed, all the asynchronized event
+    /// for it won't be scheduled by io service not matter it is
+    /// submit to io serice before or after close call. And we will
+    //. get bad_descriptor error
+    socket_->close();
+    stopped_ = true;
+}
+
+/// Post this coroutine on the ASIO service queue so that it will
+/// resume processing where it left off.  The 'done' parameter indicates
+/// whether there is an answer to return to the client.
+void
+SyncUDPServer::resume(const bool done) {
+    resume_called_ = true;
+    done_ = done;
+}
+
+bool
+SyncUDPServer::hasAnswer() {
+    return (done_);
+}
+
+} // namespace asiodns
+} // namespace isc

+ 161 - 0
src/lib/asiodns/sync_udp_server.h

@@ -0,0 +1,161 @@
+// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __SYNC_UDP_SERVER_H
+#define __SYNC_UDP_SERVER_H 1
+
+#ifndef ASIO_HPP
+#error "asio.hpp must be included before including this, see asiolink.h as to why"
+#endif
+
+#include "dns_answer.h"
+#include "dns_lookup.h"
+#include "dns_server.h"
+
+#include <dns/message.h>
+#include <asiolink/simple_callback.h>
+#include <util/buffer.h>
+#include <exceptions/exceptions.h>
+
+#include <boost/noncopyable.hpp>
+
+#include <stdint.h>
+
+namespace isc {
+namespace asiodns {
+
+/// \brief An UDP server that doesn't asynchronous lookup handlers.
+///
+/// That means, the lookup handler must provide the answer right away.
+/// This allows for implementation with less overhead, compared with
+/// the UDPClass.
+class SyncUDPServer : public DNSServer, public boost::noncopyable {
+public:
+    /// \brief Constructor
+    /// \param io_service the asio::io_service to work with
+    /// \param addr the IP address to listen for queries on
+    /// \param port the port to listen for queries on
+    /// \param checkin the callbackprovider for non-DNS events
+    /// \param lookup the callbackprovider for DNS lookup events
+    /// \param answer the callbackprovider for DNS answer events
+    explicit SyncUDPServer(asio::io_service& io_service,
+                           const asio::ip::address& addr, const uint16_t port,
+                           isc::asiolink::SimpleCallback* checkin = NULL,
+                           DNSLookup* lookup = NULL,
+                           DNSAnswer* answer = NULL);
+
+    /// \brief Constructor
+    /// \param io_service the asio::io_service to work with
+    /// \param fd the file descriptor of opened UDP socket
+    /// \param af address family, either AF_INET or AF_INET6
+    /// \param checkin the callbackprovider for non-DNS events
+    /// \param lookup the callbackprovider for DNS lookup events
+    /// \param answer the callbackprovider for DNS answer events
+    /// \throw isc::InvalidParameter if af is neither AF_INET nor AF_INET6
+    /// \throw isc::asiolink::IOError when a low-level error happens, like the
+    ///     fd is not a valid descriptor.
+    SyncUDPServer(asio::io_service& io_service, const int fd, const int af,
+                  isc::asiolink::SimpleCallback* checkin = NULL,
+                  DNSLookup* lookup = NULL, DNSAnswer* answer = NULL);
+
+    /// \brief Start the SyncUDPServer.
+    ///
+    /// This is the function operator to keep interface with other server
+    /// classes. They need that because they're coroutines.
+    virtual void operator()(asio::error_code ec = asio::error_code(),
+                    size_t length = 0);
+
+    /// \brief Calls the lookup callback
+    virtual void asyncLookup() {
+        isc_throw(Unexpected,
+                  "SyncUDPServer doesn't support asyncLookup by design, use "
+                  "UDPServer if you need it.");
+    }
+
+    /// \brief Stop the running server
+    /// \note once the server stopped, it can't restart
+    virtual void stop();
+
+    /// \brief Resume operation
+    ///
+    /// Note that unlike other servers, this one expects it to be called
+    /// directly from the lookup callback. If it isn't, the server will
+    /// throw an Unexpected exception (probably to the event loop, which
+    /// would usually lead to termination of the program, but that's OK,
+    /// as it would be serious programmer error).
+    ///
+    /// \param done Set this to true if the lookup action is done and
+    ///        we have an answer
+    virtual void resume(const bool done);
+
+    /// \brief Check if we have an answer
+    ///
+    /// \return true if we have an answer
+    virtual bool hasAnswer();
+
+    /// \brief Clones the object
+    ///
+    /// Since cloning is for the use of coroutines, the synchronous UDP server
+    /// does not need to be cloned. Therefore supporting it would be needless
+    /// work, and trying to clone it would be a programmer error anyway, this
+    /// throws Unexpected.
+    ///
+    /// \return a newly allocated copy of this object
+    virtual DNSServer* clone() {
+        isc_throw(Unexpected, "SyncUDPServer can't be cloned.");
+    }
+private:
+    // Internal state & buffers. We don't use the PIMPL idiom, as this class
+    // isn't usually used directly anyway.
+
+    // Maximum size of incoming UDP packet
+    static const size_t MAX_LENGTH = 4096;
+    // Buffer for incoming data
+    uint8_t data_[MAX_LENGTH];
+    // The buffer to render the output to and send it.
+    // If it was OK to have just a buffer, not the wrapper class,
+    // we could reuse the data_
+    isc::util::OutputBufferPtr output_buffer_;
+    // Objects to hold the query message and the answer
+    isc::dns::MessagePtr query_, answer_;
+    // The socket used for the communication
+    std::auto_ptr<asio::ip::udp::socket> socket_;
+    // The event loop we use
+    asio::io_service& io_;
+    // Place the socket puts the sender of a packet when it is received
+    asio::ip::udp::endpoint sender_;
+    // Callbacks
+    const asiolink::SimpleCallback* checkin_callback_;
+    const DNSLookup* lookup_callback_;
+    const DNSAnswer* answer_callback_;
+    // Answers from the lookup callback (not sent directly, but signalled
+    // through resume()
+    bool resume_called_, done_;
+    // This turns true when the server stops. Allows for not sending the
+    // answer after we closed the socket.
+    bool stopped_;
+
+    // Auxiliary functions
+
+    // Schedule next read on the socket. Just a wrapper around
+    // socket_->async_read_from with the correct parameters.
+    void scheduleRead();
+    // Callback from the socket's read call (called when there's an error or
+    // when a new packet comes).
+    void handleRead(const asio::error_code& ec, const size_t length);
+};
+
+} // namespace asiodns
+} // namespace isc
+#endif // __SYNC_UDP_SERVER_H

+ 0 - 3
src/lib/asiodns/tcp_server.h

@@ -62,9 +62,6 @@ public:
     void asyncLookup();
     void asyncLookup();
     void stop();
     void stop();
     void resume(const bool done);
     void resume(const bool done);
-    bool hasAnswer() { return (done_); }
-    int value() { return (get_value()); }
-
     DNSServer* clone() {
     DNSServer* clone() {
         TCPServer* s = new TCPServer(*this);
         TCPServer* s = new TCPServer(*this);
         return (s);
         return (s);

+ 84 - 35
src/lib/asiodns/tests/dns_server_unittest.cc

@@ -19,6 +19,7 @@
 #include <asiolink/io_endpoint.h>
 #include <asiolink/io_endpoint.h>
 #include <asiolink/io_error.h>
 #include <asiolink/io_error.h>
 #include <asiodns/udp_server.h>
 #include <asiodns/udp_server.h>
+#include <asiodns/sync_udp_server.h>
 #include <asiodns/tcp_server.h>
 #include <asiodns/tcp_server.h>
 #include <asiodns/dns_answer.h>
 #include <asiodns/dns_answer.h>
 #include <asiodns/dns_lookup.h>
 #include <asiodns/dns_lookup.h>
@@ -112,15 +113,22 @@ class DummyChecker : public SimpleCallback, public ServerStopper {
 
 
 // \brief no lookup logic at all,just provide a checkpoint to stop the server
 // \brief no lookup logic at all,just provide a checkpoint to stop the server
 class DummyLookup : public DNSLookup, public ServerStopper {
 class DummyLookup : public DNSLookup, public ServerStopper {
-    public:
-        void operator()(const IOMessage& io_message,
-                isc::dns::MessagePtr message,
-                isc::dns::MessagePtr answer_message,
-                isc::util::OutputBufferPtr buffer,
-                DNSServer* server) const {
-            stopServer();
+public:
+    DummyLookup() :
+        allow_resume_(true)
+    { }
+    void operator()(const IOMessage& io_message,
+            isc::dns::MessagePtr message,
+            isc::dns::MessagePtr answer_message,
+            isc::util::OutputBufferPtr buffer,
+            DNSServer* server) const {
+        stopServer();
+        if (allow_resume_) {
             server->resume(true);
             server->resume(true);
         }
         }
+    }
+    // If you want it not to call resume, set this to false
+    bool allow_resume_;
 };
 };
 
 
 // \brief copy the data received from user to the answer part
 // \brief copy the data received from user to the answer part
@@ -314,10 +322,11 @@ class TCPClient : public SimpleClient {
 // two servers, UDP client will only communicate with UDP server, same for TCP
 // two servers, UDP client will only communicate with UDP server, same for TCP
 // client
 // client
 //
 //
-// This is only the active part of the test. We run the test case twice, once
+// This is only the active part of the test. We run the test case four times, once
 // for each type of initialization (once when giving it the address and port,
 // for each type of initialization (once when giving it the address and port,
-// once when giving the file descriptor), to ensure it works both ways exactly
-// the same.
+// once when giving the file descriptor) multiplied by once for each type of UDP
+// server (UDPServer and SyncUDPServer), to ensure it works exactly the same.
+template<class UDPServerClass>
 class DNSServerTestBase : public::testing::Test {
 class DNSServerTestBase : public::testing::Test {
     protected:
     protected:
         DNSServerTestBase() :
         DNSServerTestBase() :
@@ -396,7 +405,7 @@ class DNSServerTestBase : public::testing::Test {
         SimpleAnswer* const answer_;
         SimpleAnswer* const answer_;
         UDPClient*    const udp_client_;
         UDPClient*    const udp_client_;
         TCPClient*    const tcp_client_;
         TCPClient*    const tcp_client_;
-        UDPServer*    udp_server_;
+        UDPServerClass* udp_server_;
         TCPServer*    tcp_server_;
         TCPServer*    tcp_server_;
 
 
         // To access them in signal handle function, the following
         // To access them in signal handle function, the following
@@ -406,18 +415,23 @@ class DNSServerTestBase : public::testing::Test {
 };
 };
 
 
 // Initialization with name and port
 // Initialization with name and port
-class AddrPortInit : public DNSServerTestBase {
+template<class UDPServerClass>
+class AddrPortInit : public DNSServerTestBase<UDPServerClass> {
 protected:
 protected:
     AddrPortInit() {
     AddrPortInit() {
-        udp_server_ = new UDPServer(service, server_address_, server_port,
-                                    checker_, lookup_, answer_);
-        tcp_server_ = new TCPServer(service, server_address_, server_port,
-                                    checker_, lookup_, answer_);
+        this->udp_server_ = new UDPServerClass(this->service,
+                                               this->server_address_,
+                                               server_port, this->checker_,
+                                               this->lookup_, this->answer_);
+        this->tcp_server_ = new TCPServer(this->service, this->server_address_,
+                                          server_port, this->checker_,
+                                          this->lookup_, this->answer_);
     }
     }
 };
 };
 
 
 // Initialization by the file descriptor
 // Initialization by the file descriptor
-class FdInit : public DNSServerTestBase {
+template<class UDPServerClass>
+class FdInit : public DNSServerTestBase<UDPServerClass> {
 private:
 private:
     // Opens the file descriptor for us
     // Opens the file descriptor for us
     // It uses the low-level C api, as it seems to be the easiest way to get
     // It uses the low-level C api, as it seems to be the easiest way to get
@@ -465,12 +479,14 @@ protected:
     void SetUp() {
     void SetUp() {
         const int fdUDP(getFd(SOCK_DGRAM));
         const int fdUDP(getFd(SOCK_DGRAM));
         ASSERT_NE(-1, fdUDP) << strerror(errno);
         ASSERT_NE(-1, fdUDP) << strerror(errno);
-        udp_server_ = new UDPServer(service, fdUDP, AF_INET6, checker_,
-                                    lookup_, answer_);
+        this->udp_server_ = new UDPServerClass(this->service, fdUDP, AF_INET6,
+                                               this->checker_, this->lookup_,
+                                               this->answer_);
         const int fdTCP(getFd(SOCK_STREAM));
         const int fdTCP(getFd(SOCK_STREAM));
         ASSERT_NE(-1, fdTCP) << strerror(errno);
         ASSERT_NE(-1, fdTCP) << strerror(errno);
-        tcp_server_ = new TCPServer(service, fdTCP, AF_INET6, checker_,
-                                    lookup_, answer_);
+        this->tcp_server_ = new TCPServer(this->service, fdTCP, AF_INET6,
+                                          this->checker_, this->lookup_,
+                                          this->answer_);
     }
     }
 };
 };
 
 
@@ -478,11 +494,24 @@ protected:
 template<class Parent>
 template<class Parent>
 class DNSServerTest : public Parent { };
 class DNSServerTest : public Parent { };
 
 
-typedef ::testing::Types<AddrPortInit, FdInit> ServerTypes;
+typedef ::testing::Types<AddrPortInit<UDPServer>, AddrPortInit<SyncUDPServer>,
+                         FdInit<UDPServer>, FdInit<SyncUDPServer> >
+    ServerTypes;
 TYPED_TEST_CASE(DNSServerTest, ServerTypes);
 TYPED_TEST_CASE(DNSServerTest, ServerTypes);
 
 
-bool DNSServerTestBase::io_service_is_time_out = false;
-asio::io_service* DNSServerTestBase::current_service(NULL);
+typedef ::testing::Types<UDPServer, SyncUDPServer> UDPServerTypes;
+TYPED_TEST_CASE(DNSServerTestBase, UDPServerTypes);
+
+template<class UDPServerClass>
+bool DNSServerTestBase<UDPServerClass>::io_service_is_time_out = false;
+template<class UDPServerClass>
+asio::io_service* DNSServerTestBase<UDPServerClass>::current_service(NULL);
+
+typedef ::testing::Types<AddrPortInit<SyncUDPServer>, FdInit<SyncUDPServer> >
+    SyncTypes;
+template<class Parent>
+class SyncServerTest : public Parent { };
+TYPED_TEST_CASE(SyncServerTest, SyncTypes);
 
 
 // Test whether server stopped successfully after client get response
 // Test whether server stopped successfully after client get response
 // client will send query and start to wait for response, once client
 // client will send query and start to wait for response, once client
@@ -608,17 +637,20 @@ TYPED_TEST(DNSServerTest, stopTCPServeMoreThanOnce) {
 }
 }
 
 
 // It raises an exception when invalid address family is passed
 // It raises an exception when invalid address family is passed
-TEST_F(DNSServerTestBase, invalidFamily) {
+// The parameter here doesn't mean anything
+TYPED_TEST(DNSServerTestBase, invalidFamily) {
     // We abuse DNSServerTestBase for this test, as we don't need the
     // We abuse DNSServerTestBase for this test, as we don't need the
     // initialization.
     // initialization.
-    EXPECT_THROW(UDPServer(service, 0, AF_UNIX, checker_, lookup_,
-                           answer_), isc::InvalidParameter);
-    EXPECT_THROW(TCPServer(service, 0, AF_UNIX, checker_, lookup_,
-                           answer_), isc::InvalidParameter);
+    EXPECT_THROW(TypeParam(this->service, 0, AF_UNIX, this->checker_,
+                           this->lookup_, this->answer_),
+                 isc::InvalidParameter);
+    EXPECT_THROW(TCPServer(this->service, 0, AF_UNIX, this->checker_,
+                           this->lookup_, this->answer_),
+                 isc::InvalidParameter);
 }
 }
 
 
 // It raises an exception when invalid address family is passed
 // It raises an exception when invalid address family is passed
-TEST_F(DNSServerTestBase, invalidTCPFD) {
+TYPED_TEST(DNSServerTestBase, invalidTCPFD) {
     // We abuse DNSServerTestBase for this test, as we don't need the
     // We abuse DNSServerTestBase for this test, as we don't need the
     // initialization.
     // initialization.
     /*
     /*
@@ -630,11 +662,12 @@ TEST_F(DNSServerTestBase, invalidTCPFD) {
     EXPECT_THROW(UDPServer(service, -1, AF_INET, checker_, lookup_,
     EXPECT_THROW(UDPServer(service, -1, AF_INET, checker_, lookup_,
                            answer_), isc::asiolink::IOError);
                            answer_), isc::asiolink::IOError);
     */
     */
-    EXPECT_THROW(TCPServer(service, -1, AF_INET, checker_, lookup_,
-                           answer_), isc::asiolink::IOError);
+    EXPECT_THROW(TCPServer(this->service, -1, AF_INET, this->checker_,
+                           this->lookup_, this->answer_),
+                 isc::asiolink::IOError);
 }
 }
 
 
-TEST_F(DNSServerTestBase, DISABLED_invalidUDPFD) {
+TYPED_TEST(DNSServerTestBase, DISABLED_invalidUDPFD) {
     /*
     /*
      FIXME: The UDP server doesn't fail reliably with an invalid FD.
      FIXME: The UDP server doesn't fail reliably with an invalid FD.
      We need to find a way to trigger it reliably (it seems epoll
      We need to find a way to trigger it reliably (it seems epoll
@@ -642,8 +675,24 @@ TEST_F(DNSServerTestBase, DISABLED_invalidUDPFD) {
      not the others, maybe we could make it run this at least on epoll-based
      not the others, maybe we could make it run this at least on epoll-based
      systems).
      systems).
     */
     */
-    EXPECT_THROW(UDPServer(service, -1, AF_INET, checker_, lookup_,
-                           answer_), isc::asiolink::IOError);
+    EXPECT_THROW(TypeParam(this->service, -1, AF_INET, this->checker_,
+                           this->lookup_, this->answer_),
+                 isc::asiolink::IOError);
+}
+
+// Check it rejects some of the unsupported operatirons
+TYPED_TEST(SyncServerTest, unsupportedOps) {
+    EXPECT_THROW(this->udp_server_->clone(), isc::Unexpected);
+    EXPECT_THROW(this->udp_server_->asyncLookup(), isc::Unexpected);
+}
+
+// Check it rejects forgotten resume (eg. insists that it is synchronous)
+TYPED_TEST(SyncServerTest, mustResume) {
+    this->lookup_->allow_resume_ = false;
+    ASSERT_THROW(this->testStopServerByStopper(this->udp_server_,
+                                               this->udp_client_,
+                                               this->lookup_),
+                 isc::Unexpected);
 }
 }
 
 
 }
 }

+ 0 - 5
src/lib/asiodns/udp_server.cc

@@ -343,10 +343,5 @@ UDPServer::resume(const bool done) {
     data_->io_.post(*this);
     data_->io_.post(*this);
 }
 }
 
 
-bool
-UDPServer::hasAnswer() {
-    return (data_->done_);
-}
-
 } // namespace asiodns
 } // namespace asiodns
 } // namespace isc
 } // namespace isc

+ 0 - 10
src/lib/asiodns/udp_server.h

@@ -83,16 +83,6 @@ public:
     ///        we have an answer
     ///        we have an answer
     void resume(const bool done);
     void resume(const bool done);
 
 
-    /// \brief Check if we have an answer
-    ///
-    /// \return true if we have an answer
-    bool hasAnswer();
-
-    /// \brief Returns the coroutine state value
-    ///
-    /// \return the coroutine state value
-    int value() { return (get_value()); }
-
     /// \brief Clones the object
     /// \brief Clones the object
     ///
     ///
     /// \return a newly allocated copy of this object
     /// \return a newly allocated copy of this object