Browse Source

experimental UDP/TCP auth server using boost::asio

git-svn-id: svn://bind10.isc.org/svn/bind10/branches/jinmei-asio@1195 e5f2f494-b856-4b98-b285-d166d9295462
JINMEI Tatuya 15 years ago
parent
commit
14297b86e7

+ 44 - 0
configure.ac

@@ -12,6 +12,10 @@ AC_PROG_CXX
 AC_PROG_CC
 AC_PROG_LIBTOOL
 
+# Use C++ language
+AC_LANG_CPLUSPLUS
+AX_COMPILER_VENDOR
+
 m4_define([_AM_PYTHON_INTERPRETER_LIST], [python python3 python3.1])
 AM_PATH_PYTHON([3.1])
 
@@ -86,6 +90,46 @@ if test "$lcov" != "no"; then
 fi
 AC_SUBST(USE_LCOV)
 
+# Check availability of the Boost System library
+
+AC_MSG_CHECKING([for boost::system library])
+AC_ARG_WITH([boostlib],
+AC_HELP_STRING([--with-boostlib=PATH],
+  [specify a path to boost libraries if it is not automatically found]),
+  [boostlib_path="$withval"], [boostlib_path="no"])
+if test "$boostlib_path" != "no"; then
+	BOOST_LDFLAGS="-L$boostlib_path"
+fi
+
+LDFLAGS_SAVED="$LDFLAGS"
+LIBS_SAVED="$LIBS"
+CPPFLAGS_SAVED="$CPPFLAGS"
+CPPFLAGS="$CPPFLAGS -Iext"
+
+for BOOST_TRY_LIB in boost_system boost_system-mt; do
+	LDFLAGS="$LDFLAGS_SAVED ${BOOST_LDFLAGS}"
+	LIBS="$LIBS_SAVED -l${BOOST_TRY_LIB}"
+	AC_TRY_LINK([#include <boost/system/error_code.hpp>],
+		[ boost::system::error_code error_code;
+		  std::string message(error_code.message());
+		  return 0; ],
+	[ AC_MSG_RESULT(ok)
+	  BOOST_SYSTEM_LIB="-l${BOOST_TRY_LIB}"
+	  ],[])
+	if test "X${BOOST_SYSTEM_LIB}" != X; then
+        	break
+	fi
+done
+
+if test "X${BOOST_SYSTEM_LIB}" = X; then
+	AC_MSG_RESULT(not found)
+	AC_MSG_ERROR(Unable to link with the boost::system library)
+fi
+
+CPPFLAGS="$CPPFLAGS_SAVED"
+LIBS="$LIBS_SAVED"
+AC_SUBST(BOOST_SYSTEM_LIB)
+
 #
 # Check availability of gtest, which will be used for unit tests.
 #

+ 75 - 0
ext/boost/system/config.hpp

@@ -0,0 +1,75 @@
+//  boost/system/config.hpp  -------------------------------------------------//
+
+//  Copyright Beman Dawes 2003, 2006
+
+//  Distributed under the Boost Software License, Version 1.0. (See accompanying
+//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+//  See http://www.boost.org/libs/system for documentation.
+
+#ifndef BOOST_SYSTEM_CONFIG_HPP                  
+#define BOOST_SYSTEM_CONFIG_HPP
+
+#include <boost/config.hpp>
+
+//  BOOST_POSIX_API or BOOST_WINDOWS_API specify which API to use.
+//  If not specified, a sensible default will be applied.
+
+# if defined( BOOST_WINDOWS_API ) && defined( BOOST_POSIX_API )
+#   error both BOOST_WINDOWS_API and BOOST_POSIX_API are defined
+# elif !defined( BOOST_WINDOWS_API ) && !defined( BOOST_POSIX_API )
+#   if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__CYGWIN__)
+#     define BOOST_WINDOWS_API
+#   else
+#     define BOOST_POSIX_API 
+#   endif
+# endif
+
+//  enable dynamic linking on Windows  ---------------------------------------//
+
+//#  if (defined(BOOST_ALL_DYN_LINK) || defined(BOOST_SYSTEM_DYN_LINK)) && defined(__BORLANDC__) && defined(__WIN32__)
+//#    error Dynamic linking Boost.System does not work for Borland; use static linking instead
+//#  endif
+
+#ifdef BOOST_HAS_DECLSPEC // defined in config system
+// we need to import/export our code only if the user has specifically
+// asked for it by defining either BOOST_ALL_DYN_LINK if they want all boost
+// libraries to be dynamically linked, or BOOST_SYSTEM_DYN_LINK
+// if they want just this one to be dynamically liked:
+#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_SYSTEM_DYN_LINK)
+// export if this is our own source, otherwise import:
+#ifdef BOOST_SYSTEM_SOURCE
+# define BOOST_SYSTEM_DECL __declspec(dllexport)
+#else
+# define BOOST_SYSTEM_DECL __declspec(dllimport)
+#endif  // BOOST_SYSTEM_SOURCE
+#endif  // DYN_LINK
+#endif  // BOOST_HAS_DECLSPEC
+//
+// if BOOST_SYSTEM_DECL isn't defined yet define it now:
+#ifndef BOOST_SYSTEM_DECL
+#define BOOST_SYSTEM_DECL
+#endif
+
+//  enable automatic library variant selection  ------------------------------// 
+
+#if !defined(BOOST_SYSTEM_SOURCE) && !defined(BOOST_ALL_NO_LIB) && !defined(BOOST_SYSTEM_NO_LIB)
+//
+// Set the name of our library, this will get undef'ed by auto_link.hpp
+// once it's done with it:
+//
+#define BOOST_LIB_NAME boost_system
+//
+// If we're importing code from a dll, then tell auto_link.hpp about it:
+//
+#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_SYSTEM_DYN_LINK)
+#  define BOOST_DYN_LINK
+#endif
+//
+// And include the header that does the work:
+//
+#include <boost/config/auto_link.hpp>
+#endif  // auto-linking disabled
+
+#endif // BOOST_SYSTEM_CONFIG_HPP
+

+ 56 - 0
ext/boost/system/cygwin_error.hpp

@@ -0,0 +1,56 @@
+//  boost/system/cygwin_error.hpp  -------------------------------------------//
+
+//  Copyright Beman Dawes 2007
+
+//  Distributed under the Boost Software License, Version 1.0. (See accompanying
+//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+//  See library home page at http://www.boost.org/libs/system
+
+#ifndef BOOST_CYGWIN_ERROR_HPP
+#define BOOST_CYGWIN_ERROR_HPP
+
+//  This header is effectively empty for compiles on operating systems where
+//  it is not applicable.
+
+# ifdef __CYGWIN__
+
+#include <boost/system/error_code.hpp>
+
+namespace boost
+{
+  namespace system
+  {
+    //  To construct an error_code after a API error:
+    //
+    //      error_code( errno, system_category )
+
+    //  User code should use the portable "posix" enums for POSIX errors; this
+    //  allows such code to be portable to non-POSIX systems. For the non-POSIX
+    //  errno values that POSIX-based systems typically provide in addition to 
+    //  POSIX values, use the system specific enums below.
+
+   namespace cygwin_error
+    {
+      enum cygwin_errno
+      {
+        no_net = ENONET,
+        no_package = ENOPKG,
+        no_share = ENOSHARE
+      };
+    }  // namespace cygwin_error
+
+    template<> struct is_error_code_enum<cygwin_error::cygwin_errno>
+      { static const bool value = true; };
+
+    namespace cygwin_error
+    {
+      inline error_code make_error_code( cygwin_errno e )
+        { return error_code( e, get_system_category() ); }
+    }
+  }
+}
+
+#endif  // __CYGWIN__
+
+#endif  // BOOST_CYGWIN_ERROR_HPP

+ 523 - 0
ext/boost/system/error_code.hpp

@@ -0,0 +1,523 @@
+//  boost/system/error_code.hpp  ---------------------------------------------//
+
+//  Copyright Beman Dawes 2006, 2007
+//  Copyright Christoper Kohlhoff 2007
+
+//  Distributed under the Boost Software License, Version 1.0. (See accompanying
+//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+//  See library home page at http://www.boost.org/libs/system
+
+#ifndef BOOST_ERROR_CODE_HPP
+#define BOOST_ERROR_CODE_HPP
+
+#include <boost/system/config.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/assert.hpp>
+#include <boost/operators.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/utility/enable_if.hpp>
+#include <ostream>
+#include <string>
+#include <stdexcept>
+#include <functional>
+
+// TODO: undef these macros if not already defined
+#include <boost/cerrno.hpp> 
+
+#if !defined(BOOST_POSIX_API) && !defined(BOOST_WINDOWS_API)
+#  error BOOST_POSIX_API or BOOST_WINDOWS_API must be defined
+#endif
+
+#include <boost/config/abi_prefix.hpp> // must be the last #include
+
+namespace boost
+{
+  namespace system
+  {
+
+    class error_code;
+    class error_condition;
+
+    //  "Concept" helpers  ---------------------------------------------------//
+
+    template< class T >
+    struct is_error_code_enum { static const bool value = false; };
+
+    template< class T >
+    struct is_error_condition_enum { static const bool value = false; };
+
+    //  generic error_conditions  --------------------------------------------//
+
+    namespace errc
+    {
+      enum errc_t
+      {
+        success = 0,
+        address_family_not_supported = EAFNOSUPPORT,
+        address_in_use = EADDRINUSE,
+        address_not_available = EADDRNOTAVAIL,
+        already_connected = EISCONN,
+        argument_list_too_long = E2BIG,
+        argument_out_of_domain = EDOM,
+        bad_address = EFAULT,
+        bad_file_descriptor = EBADF,
+        bad_message = EBADMSG,
+        broken_pipe = EPIPE,
+        connection_aborted = ECONNABORTED,
+        connection_already_in_progress = EALREADY,
+        connection_refused = ECONNREFUSED,
+        connection_reset = ECONNRESET,
+        cross_device_link = EXDEV,
+        destination_address_required = EDESTADDRREQ,
+        device_or_resource_busy = EBUSY,
+        directory_not_empty = ENOTEMPTY,
+        executable_format_error = ENOEXEC,
+        file_exists = EEXIST,
+        file_too_large = EFBIG,
+        filename_too_long = ENAMETOOLONG,
+        function_not_supported = ENOSYS,
+        host_unreachable = EHOSTUNREACH,
+        identifier_removed = EIDRM,
+        illegal_byte_sequence = EILSEQ,
+        inappropriate_io_control_operation = ENOTTY,
+        interrupted = EINTR,
+        invalid_argument = EINVAL,
+        invalid_seek = ESPIPE,
+        io_error = EIO,
+        is_a_directory = EISDIR,
+        message_size = EMSGSIZE,
+        network_down = ENETDOWN,
+        network_reset = ENETRESET,
+        network_unreachable = ENETUNREACH,
+        no_buffer_space = ENOBUFS,
+        no_child_process = ECHILD,
+        no_link = ENOLINK,
+        no_lock_available = ENOLCK,
+        no_message_available = ENODATA,
+        no_message = ENOMSG,
+        no_protocol_option = ENOPROTOOPT,
+        no_space_on_device = ENOSPC,
+        no_stream_resources = ENOSR,
+        no_such_device_or_address = ENXIO,
+        no_such_device = ENODEV,
+        no_such_file_or_directory = ENOENT,
+        no_such_process = ESRCH,
+        not_a_directory = ENOTDIR,
+        not_a_socket = ENOTSOCK,
+        not_a_stream = ENOSTR,
+        not_connected = ENOTCONN,
+        not_enough_memory = ENOMEM,
+        not_supported = ENOTSUP,
+        operation_canceled = ECANCELED,
+        operation_in_progress = EINPROGRESS,
+        operation_not_permitted = EPERM,
+        operation_not_supported = EOPNOTSUPP,
+        operation_would_block = EWOULDBLOCK,
+        owner_dead = EOWNERDEAD,
+        permission_denied = EACCES,
+        protocol_error = EPROTO,
+        protocol_not_supported = EPROTONOSUPPORT,
+        read_only_file_system = EROFS,
+        resource_deadlock_would_occur = EDEADLK,
+        resource_unavailable_try_again = EAGAIN,
+        result_out_of_range = ERANGE,
+        state_not_recoverable = ENOTRECOVERABLE,
+        stream_timeout = ETIME,
+        text_file_busy = ETXTBSY,
+        timed_out = ETIMEDOUT,
+        too_many_files_open_in_system = ENFILE,
+        too_many_files_open = EMFILE,
+        too_many_links = EMLINK,
+        too_many_synbolic_link_levels = ELOOP,
+        value_too_large = EOVERFLOW,
+        wrong_protocol_type = EPROTOTYPE
+      };
+
+    } // namespace errc
+
+# ifndef BOOST_SYSTEM_NO_DEPRECATED
+    namespace posix = errc;
+    namespace posix_error = errc;
+# endif
+
+    template<> struct is_error_condition_enum<errc::errc_t>
+      { static const bool value = true; };
+
+
+    //  ----------------------------------------------------------------------//
+
+    //  Operating system specific interfaces  --------------------------------//
+
+
+    //  The interface is divided into general and system-specific portions to
+    //  meet these requirements:
+    //
+    //  * Code calling an operating system API can create an error_code with
+    //    a single category (system_category), even for POSIX-like operating
+    //    systems that return some POSIX errno values and some native errno
+    //    values. This code should not have to pay the cost of distinguishing
+    //    between categories, since it is not yet known if that is needed.
+    //
+    //  * Users wishing to write system-specific code should be given enums for
+    //    at least the common error cases.
+    //
+    //  * System specific code should fail at compile time if moved to another
+    //    operating system.
+
+    //  The system specific portions of the interface are located in headers
+    //  with names reflecting the operating system. For example,
+    //
+    //       <boost/system/cygwin_error.hpp>
+    //       <boost/system/linux_error.hpp>
+    //       <boost/system/windows_error.hpp>
+    //
+    //  These headers are effectively empty for compiles on operating systems
+    //  where they are not applicable.
+
+    //  ----------------------------------------------------------------------//
+
+    //  class error_category  ------------------------------------------------//
+
+    class error_category : public noncopyable
+    {
+    public:
+      virtual ~error_category(){}
+      virtual inline const char *    name() const;  // see implementation note below
+      virtual inline std::string     message( int ev ) const;   // see implementation note below
+      virtual inline error_condition default_error_condition( int ev ) const;
+      virtual inline bool equivalent( int code, const error_condition & condition ) const;
+      virtual inline bool equivalent( const error_code & code, int condition ) const;
+
+      bool operator==(const error_category & rhs) const { return this == &rhs; }
+      bool operator!=(const error_category & rhs) const { return this != &rhs; }
+      bool operator<( const error_category & rhs ) const
+      {
+        return std::less<const error_category*>()( this, &rhs );
+      }
+    };
+
+    //  predefined error categories  -----------------------------------------//
+
+    BOOST_SYSTEM_DECL const error_category &  get_system_category();
+    BOOST_SYSTEM_DECL const error_category &  get_generic_category();
+
+    static const error_category &  system_category = get_system_category();
+    static const error_category &  generic_category = get_generic_category();
+    
+# ifndef BOOST_SYSTEM_NO_DEPRECATED
+    //  deprecated synonyms
+    inline const error_category &  get_posix_category() { return get_generic_category(); }
+    static const error_category &  posix_category = get_generic_category();
+    static const error_category &  errno_ecat     = get_generic_category();
+    static const error_category &  native_ecat    = get_system_category();
+# endif
+
+    //  class error_condition  -----------------------------------------------//
+
+    //  error_conditions are portable, error_codes are system or library specific
+
+    class error_condition
+    {
+    public:
+
+      // constructors:
+      error_condition() : m_val(0), m_cat(&get_generic_category()) {}
+      error_condition( int val, const error_category & cat ) : m_val(val), m_cat(&cat) {}
+
+      template <class ErrorConditionEnum>
+        error_condition(ErrorConditionEnum e,
+          typename boost::enable_if<is_error_condition_enum<ErrorConditionEnum> >::type* = 0)
+      {
+        *this = make_error_condition(e);
+      }
+
+      // modifiers:
+
+      void assign( int val, const error_category & cat )
+      { 
+        m_val = val;
+        m_cat = &cat;
+      }
+                                             
+      template<typename ErrorConditionEnum>
+        typename boost::enable_if<is_error_condition_enum<ErrorConditionEnum>, error_condition>::type &
+          operator=( ErrorConditionEnum val )
+      { 
+        *this = make_error_condition(val);
+        return *this;
+      }
+
+      void clear()
+      {
+        m_val = 0;
+        m_cat = &get_generic_category();
+      }
+
+      // observers:
+      int                     value() const    { return m_val; }
+      const error_category &  category() const { return *m_cat; }
+      std::string             message() const  { return m_cat->message(value()); }
+
+      typedef void (*unspecified_bool_type)();
+      static void unspecified_bool_true() {}
+
+      operator unspecified_bool_type() const  // true if error
+      { 
+        return m_val == 0 ? 0 : unspecified_bool_true;
+      }
+
+      bool operator!() const  // true if no error
+      {
+        return m_val == 0;
+      }
+
+      // relationals:
+      //  the more symmetrical non-member syntax allows enum
+      //  conversions work for both rhs and lhs.
+      inline friend bool operator==( const error_condition & lhs,
+                                     const error_condition & rhs )
+      {
+        return lhs.m_cat == rhs.m_cat && lhs.m_val == rhs.m_val;
+      }                  
+
+      inline friend bool operator<( const error_condition & lhs,
+                                    const error_condition & rhs )
+        //  the more symmetrical non-member syntax allows enum
+        //  conversions work for both rhs and lhs.
+      {
+        return lhs.m_cat < rhs.m_cat
+          || (lhs.m_cat == rhs.m_cat && lhs.m_val < rhs.m_val);
+      }
+
+    private:
+      int                     m_val;
+      const error_category *  m_cat;
+
+    };
+
+    //  class error_code  ----------------------------------------------------//
+
+    //  We want error_code to be a value type that can be copied without slicing
+    //  and without requiring heap allocation, but we also want it to have
+    //  polymorphic behavior based on the error category. This is achieved by
+    //  abstract base class error_category supplying the polymorphic behavior,
+    //  and error_code containing a pointer to an object of a type derived
+    //  from error_category.
+    class error_code
+    {
+    public:
+
+      // constructors:
+      error_code() : m_val(0), m_cat(&get_system_category()) {}
+      error_code( int val, const error_category & cat ) : m_val(val), m_cat(&cat) {}
+
+      template <class ErrorCodeEnum>
+        error_code(ErrorCodeEnum e,
+          typename boost::enable_if<is_error_code_enum<ErrorCodeEnum> >::type* = 0)
+      {
+        *this = make_error_code(e);
+      }
+
+      // modifiers:
+      void assign( int val, const error_category & cat )
+      { 
+        m_val = val;
+        m_cat = &cat;
+      }
+                                             
+      template<typename ErrorCodeEnum>
+        typename boost::enable_if<is_error_code_enum<ErrorCodeEnum>, error_code>::type &
+          operator=( ErrorCodeEnum val )
+      { 
+        *this = make_error_code(val);
+        return *this;
+      }
+
+      void clear()
+      {
+        m_val = 0;
+        m_cat = &get_system_category();
+      }
+
+      // observers:
+      int                     value() const    { return m_val; }
+      const error_category &  category() const { return *m_cat; }
+      error_condition         default_error_condition() const  { return m_cat->default_error_condition(value()); }
+      std::string             message() const  { return m_cat->message(value()); }
+
+      typedef void (*unspecified_bool_type)();
+      static void unspecified_bool_true() {}
+
+      operator unspecified_bool_type() const  // true if error
+      { 
+        return m_val == 0 ? 0 : unspecified_bool_true;
+      }
+
+      bool operator!() const  // true if no error
+      {
+        return m_val == 0;
+      }
+
+      // relationals:
+      inline friend bool operator==( const error_code & lhs,
+                                     const error_code & rhs )
+        //  the more symmetrical non-member syntax allows enum
+        //  conversions work for both rhs and lhs.
+      {
+        return lhs.m_cat == rhs.m_cat && lhs.m_val == rhs.m_val;
+      }
+
+      inline friend bool operator<( const error_code & lhs,
+                                    const error_code & rhs )
+        //  the more symmetrical non-member syntax allows enum
+        //  conversions work for both rhs and lhs.
+      {
+        return lhs.m_cat < rhs.m_cat
+          || (lhs.m_cat == rhs.m_cat && lhs.m_val < rhs.m_val);
+      }
+                  
+      private:
+      int                     m_val;
+      const error_category *  m_cat;
+
+    };
+
+    //  predefined error_code object used as "throw on error" tag
+# ifndef BOOST_SYSTEM_NO_DEPRECATED
+    BOOST_SYSTEM_DECL extern error_code throws;
+# endif
+
+    //  Moving from a "throws" object to a "throws" function without breaking
+    //  existing code is a bit of a problem. The workaround is to place the
+    //  "throws" function in namespace boost rather than namespace boost::system.
+
+  }  // namespace system
+
+  namespace detail { inline system::error_code * throws() { return 0; } }
+    //  Misuse of the error_code object is turned into a noisy failure by
+    //  poisoning the reference. This particular implementation doesn't
+    //  produce warnings or errors from popular compilers, is very efficient
+    //  (as determined by inspecting generated code), and does not suffer
+    //  from order of initialization problems. In practice, it also seems
+    //  cause user function error handling implementation errors to be detected
+    //  very early in the development cycle.
+
+  inline system::error_code & throws()
+    { return *detail::throws(); }
+
+  namespace system
+  {
+    //  non-member functions  ------------------------------------------------//
+
+    inline bool operator!=( const error_code & lhs,
+                            const error_code & rhs )
+    {
+      return !(lhs == rhs);
+    }
+
+    inline bool operator!=( const error_condition & lhs,
+                            const error_condition & rhs )
+    {
+      return !(lhs == rhs);
+    }
+
+    inline bool operator==( const error_code & code,
+                            const error_condition & condition )
+    {
+      return code.category().equivalent( code.value(), condition )
+        || condition.category().equivalent( code, condition.value() );
+    }
+                
+    inline bool operator!=( const error_code & lhs,
+                            const error_condition & rhs )
+    {
+      return !(lhs == rhs);
+    }
+                
+    inline bool operator==( const error_condition & condition,
+                            const error_code & code )
+    {
+      return condition.category().equivalent( code, condition.value() )
+        || code.category().equivalent( code.value(), condition );
+    }
+                
+    inline bool operator!=( const error_condition & lhs,
+                            const error_code & rhs )
+    {
+      return !(lhs == rhs);
+    }
+                  
+    // TODO: both of these may move elsewhere, but the LWG hasn't spoken yet.
+
+    template <class charT, class traits>
+    inline std::basic_ostream<charT,traits>&
+      operator<< (std::basic_ostream<charT,traits>& os, error_code ec)
+    {
+      os << ec.category().name() << ':' << ec.value();
+      return os;
+    }
+
+    inline std::size_t hash_value( const error_code & ec )
+    {
+      return static_cast<std::size_t>(ec.value())
+        + reinterpret_cast<std::size_t>(&ec.category());
+    }
+
+    //  make_* functions for errc::errc_t  -----------------------------//
+
+    namespace errc
+    {
+      //  explicit conversion:
+      inline error_code make_error_code( errc_t e )
+        { return error_code( e, get_generic_category() ); }
+
+      //  implicit conversion:
+      inline error_condition make_error_condition( errc_t e )
+        { return error_condition( e, get_generic_category() ); }
+    }
+
+    //  error_category default implementation  -------------------------------//
+
+    inline error_condition error_category::default_error_condition( int ev ) const
+    { 
+      return error_condition( ev, *this );
+    }
+
+    inline bool error_category::equivalent( int code,
+      const error_condition & condition ) const
+    {
+      return default_error_condition( code ) == condition;
+    }
+
+    inline bool error_category::equivalent( const error_code & code,
+      int condition ) const
+    {
+      return *this == code.category() && code.value() == condition;
+    }
+
+    //  error_category implementation note: VC++ 8.0 objects to name() and
+    //  message() being pure virtual functions. Thus these implementations.
+    inline const char * error_category::name() const
+    { 
+      return "error: should never be called";
+    }
+
+    inline std::string error_category::message( int ) const
+    { 
+      static std::string s("error: should never be called");
+      return s;
+    }
+
+  } // namespace system
+} // namespace boost
+
+#include <boost/config/abi_suffix.hpp> // pops abi_prefix.hpp pragmas
+
+# ifdef BOOST_ERROR_CODE_HEADER_ONLY
+#   include <boost/../libs/system/src/error_code.cpp>
+# endif
+
+#endif // BOOST_ERROR_CODE_HPP
+
+

+ 110 - 0
ext/boost/system/linux_error.hpp

@@ -0,0 +1,110 @@
+//  boost/system/linux_error.hpp  -------------------------------------------//
+
+//  Copyright Beman Dawes 2007
+
+//  Distributed under the Boost Software License, Version 1.0. (See accompanying
+//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+//  See library home page at http://www.boost.org/libs/system
+
+#ifndef BOOST_LINUX_ERROR_HPP
+#define BOOST_LINUX_ERROR_HPP
+
+//  This header is effectively empty for compiles on operating systems where
+//  it is not applicable.
+
+#if defined(linux) || defined(__linux) || defined(__linux__)
+
+#include <boost/system/error_code.hpp>
+
+namespace boost
+{
+  namespace system
+  {
+    //  To construct an error_code after a API error:
+    //
+    //      error_code( errno, system_category )
+
+    //  User code should use the portable "posix" enums for POSIX errors; this
+    //  allows such code to be portable to non-POSIX systems. For the non-POSIX
+    //  errno values that POSIX-based systems typically provide in addition to 
+    //  POSIX values, use the system specific enums below.
+
+    namespace linux_error
+    {
+      enum linux_errno
+      {
+        advertise_error = EADV,
+        bad_exchange = EBADE,
+        bad_file_number = EBADFD,
+        bad_font_format = EBFONT,
+        bad_request_code = EBADRQC,
+        bad_request_descriptor = EBADR,
+        bad_slot = EBADSLT,
+        channel_range = ECHRNG,
+        communication_error = ECOMM,
+        dot_dot_error = EDOTDOT,
+        exchange_full = EXFULL,
+        host_down = EHOSTDOWN,
+        is_named_file_type= EISNAM,
+        key_expired = EKEYEXPIRED,
+        key_rejected = EKEYREJECTED,
+        key_revoked = EKEYREVOKED,
+        level2_halt= EL2HLT,
+        level2_no_syncronized= EL2NSYNC,
+        level3_halt = EL3HLT,
+        level3_reset = EL3RST,
+        link_range = ELNRNG,
+        medium_type = EMEDIUMTYPE,
+        no_anode= ENOANO,
+        no_block_device = ENOTBLK,
+        no_csi = ENOCSI,
+        no_key = ENOKEY,
+        no_medium = ENOMEDIUM,
+        no_network = ENONET,
+        no_package = ENOPKG,
+        not_avail = ENAVAIL,
+        not_named_file_type= ENOTNAM,
+        not_recoverable = ENOTRECOVERABLE,
+        not_unique = ENOTUNIQ,
+        owner_dead = EOWNERDEAD,
+        protocol_no_supported = EPFNOSUPPORT,
+        remote_address_changed = EREMCHG,
+        remote_io_error = EREMOTEIO,
+        remote_object = EREMOTE,
+        restart_needed = ERESTART,
+        shared_library_access = ELIBACC,
+        shared_library_bad = ELIBBAD,
+        shared_library_execute = ELIBEXEC,
+        shared_library_max_ = ELIBMAX,
+        shared_library_section= ELIBSCN,
+        shutdown = ESHUTDOWN,
+        socket_type_not_supported = ESOCKTNOSUPPORT,
+        srmount_error = ESRMNT,
+        stream_pipe_error = ESTRPIPE,
+        too_many_references = ETOOMANYREFS,
+        too_many_users = EUSERS,
+        unattached = EUNATCH,
+        unclean = EUCLEAN
+      };
+    }  // namespace linux_error
+
+# ifndef BOOST_SYSTEM_NO_DEPRECATED
+    namespace Linux = linux_error;
+# endif
+
+    template<> struct is_error_code_enum<linux_error::linux_errno>
+      { static const bool value = true; };
+
+    namespace linux_error
+    {
+      inline error_code make_error_code( linux_errno e )
+        { return error_code( e, get_system_category() ); }
+    }
+
+  }  // namespace system
+}  // namespace boost 
+
+#endif  // Linux
+
+#endif  // BOOST_LINUX_ERROR_HPP

+ 81 - 0
ext/boost/system/system_error.hpp

@@ -0,0 +1,81 @@
+//  Boost system_error.hpp  --------------------------------------------------//
+
+//  Copyright Beman Dawes 2006
+
+//  Distributed under the Boost Software License, Version 1.0. (See accompanying
+//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_SYSTEM_ERROR_HPP
+#define BOOST_SYSTEM_ERROR_HPP
+
+#include <string>
+#include <stdexcept>
+#include <cassert>
+#include <boost/system/error_code.hpp>
+
+namespace boost
+{
+  namespace system
+  {
+    //  class system_error  --------------------------------------------------//
+
+    class system_error : public std::runtime_error
+    {
+    public:
+      system_error( error_code ec )
+          : std::runtime_error(""), m_error_code(ec) {}
+
+      system_error( error_code ec, const std::string & what_arg )
+          : std::runtime_error(what_arg), m_error_code(ec) {}
+
+      system_error( error_code ec, const char* what_arg )
+          : std::runtime_error(what_arg), m_error_code(ec) {}
+
+      system_error( int ev, const error_category & ecat )
+          : std::runtime_error(""), m_error_code(ev,ecat) {}
+
+      system_error( int ev, const error_category & ecat,
+        const std::string & what_arg )
+          : std::runtime_error(what_arg), m_error_code(ev,ecat) {}
+
+      system_error( int ev, const error_category & ecat,
+        const char * what_arg )
+          : std::runtime_error(what_arg), m_error_code(ev,ecat) {}
+
+      virtual ~system_error() throw() {}
+
+      const error_code &  code() const throw() { return m_error_code; }
+      const char *        what() const throw();
+
+    private:
+      error_code           m_error_code;
+      mutable std::string  m_what;
+    };
+
+    //  implementation  ------------------------------------------------------//
+
+    inline const char * system_error::what() const throw()
+    // see http://www.boost.org/more/error_handling.html for lazy build rationale
+    {
+      if ( m_what.empty() )
+      {
+        try
+        {
+          m_what = this->std::runtime_error::what();
+          if ( m_error_code )
+          {
+            if ( !m_what.empty() ) m_what += ": ";
+            m_what += m_error_code.message();
+          }
+        }
+        catch (...) { return std::runtime_error::what(); }
+      }
+      return m_what.c_str();
+    }
+
+  } // namespace system
+} // namespace boost
+
+#endif // BOOST_SYSTEM_ERROR_HPP
+
+

+ 118 - 0
ext/boost/system/windows_error.hpp

@@ -0,0 +1,118 @@
+//  boost/system/windows_error.hpp  ------------------------------------------//
+
+//  Copyright Beman Dawes 2007
+
+//  Distributed under the Boost Software License, Version 1.0. (See accompanying
+//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+//  See library home page at http://www.boost.org/libs/system
+
+#ifndef BOOST_WINDOWS_ERROR_HPP
+#define BOOST_WINDOWS_ERROR_HPP
+
+//  This header is effectively empty for compiles on operating systems where
+//  it is not applicable.
+
+#include <boost/system/config.hpp>
+
+#ifdef BOOST_WINDOWS_API
+
+#include <boost/system/error_code.hpp>
+#include <winerror.h>
+
+namespace boost
+{
+  namespace system
+  {
+
+    //  Microsoft Windows  ---------------------------------------------------//
+
+    //  To construct an error_code after a API error:
+    //
+    //      error_code( ::GetLastError(), system_category )
+
+    namespace windows_error
+    {
+      enum windows_error_code
+      {
+        success = 0,
+        // These names and values are based on Windows winerror.h
+        invalid_function = ERROR_INVALID_FUNCTION,
+        file_not_found = ERROR_FILE_NOT_FOUND,
+        path_not_found = ERROR_PATH_NOT_FOUND,
+        too_many_open_files = ERROR_TOO_MANY_OPEN_FILES,
+        access_denied = ERROR_ACCESS_DENIED,
+        invalid_handle = ERROR_INVALID_HANDLE,
+        arena_trashed = ERROR_ARENA_TRASHED,
+        not_enough_memory = ERROR_NOT_ENOUGH_MEMORY,
+        invalid_block = ERROR_INVALID_BLOCK,
+        bad_environment = ERROR_BAD_ENVIRONMENT,
+        bad_format = ERROR_BAD_FORMAT,
+        invalid_access = ERROR_INVALID_ACCESS,
+        outofmemory = ERROR_OUTOFMEMORY,
+        invalid_drive = ERROR_INVALID_DRIVE,
+        current_directory = ERROR_CURRENT_DIRECTORY,
+        not_same_device = ERROR_NOT_SAME_DEVICE,
+        no_more_files = ERROR_NO_MORE_FILES,
+        write_protect = ERROR_WRITE_PROTECT,
+        bad_unit = ERROR_BAD_UNIT,
+        not_ready = ERROR_NOT_READY,
+        bad_command = ERROR_BAD_COMMAND,
+        crc = ERROR_CRC,
+        bad_length = ERROR_BAD_LENGTH,
+        seek = ERROR_SEEK,
+        not_dos_disk = ERROR_NOT_DOS_DISK,
+        sector_not_found = ERROR_SECTOR_NOT_FOUND,
+        out_of_paper = ERROR_OUT_OF_PAPER,
+        write_fault = ERROR_WRITE_FAULT,
+        read_fault = ERROR_READ_FAULT,
+        gen_failure = ERROR_GEN_FAILURE,
+        sharing_violation = ERROR_SHARING_VIOLATION,
+        lock_violation = ERROR_LOCK_VIOLATION,
+        wrong_disk = ERROR_WRONG_DISK,
+        sharing_buffer_exceeded = ERROR_SHARING_BUFFER_EXCEEDED,
+        handle_eof = ERROR_HANDLE_EOF,
+        handle_disk_full= ERROR_HANDLE_DISK_FULL,
+        rem_not_list = ERROR_REM_NOT_LIST,
+        dup_name = ERROR_DUP_NAME,
+        bad_net_path = ERROR_BAD_NETPATH,
+        network_busy = ERROR_NETWORK_BUSY,
+        // ...
+        file_exists = ERROR_FILE_EXISTS,
+        cannot_make = ERROR_CANNOT_MAKE,
+        // ...
+        broken_pipe = ERROR_BROKEN_PIPE,
+        open_failed = ERROR_OPEN_FAILED,
+        buffer_overflow = ERROR_BUFFER_OVERFLOW,
+        disk_full= ERROR_DISK_FULL,
+        // ...
+        lock_failed = ERROR_LOCK_FAILED,
+        busy = ERROR_BUSY,
+        cancel_violation = ERROR_CANCEL_VIOLATION,
+        already_exists = ERROR_ALREADY_EXISTS
+        // ...
+
+        // TODO: add more Windows errors
+      };
+
+    }  // namespace windows
+
+# ifndef BOOST_SYSTEM_NO_DEPRECATED
+    namespace windows = windows_error;
+# endif
+
+    template<> struct is_error_code_enum<windows_error::windows_error_code>
+      { static const bool value = true; };
+
+    namespace windows_error
+    {
+      inline error_code make_error_code( windows_error_code e )
+        { return error_code( e, get_system_category() ); }
+    }
+
+  }  // namespace system
+}  // namespace boost
+
+#endif  // BOOST_WINDOWS_API
+
+#endif  // BOOST_WINDOWS_ERROR_HPP

+ 1 - 0
src/bin/auth/Makefile.am

@@ -14,6 +14,7 @@ b10_auth_LDADD += $(top_builddir)/src/lib/config/libcfgclient.a
 b10_auth_LDADD += $(top_builddir)/src/lib/cc/libcc.a
 b10_auth_LDADD += $(top_builddir)/src/lib/exceptions/.libs/libexceptions.a
 b10_auth_LDADD += $(SQLITE_LIBS)
+b10_auth_LDADD += $(BOOST_SYSTEM_LIB)
 
 # TODO: config.h.in is wrong because doesn't honor pkgdatadir
 # and can't use @datadir@ because doesn't expand default ${prefix}

+ 31 - 42
src/bin/auth/auth_srv.cc

@@ -84,52 +84,41 @@ AuthSrv::~AuthSrv()
     delete impl_;
 }
 
-void
-AuthSrv::processMessage(const int fd)
+int
+AuthSrv::processMessage(InputBuffer& request_buffer,
+                        Message& message,
+                        MessageRenderer& response_renderer)
 {
-    struct sockaddr_storage ss;
-    socklen_t sa_len = sizeof(ss);
-    struct sockaddr* sa = static_cast<struct sockaddr*>((void*)&ss);
-    char recvbuf[4096];
-    int cc;
-
-    if ((cc = recvfrom(fd, recvbuf, sizeof(recvbuf), 0, sa, &sa_len)) > 0) {
-        Message msg(Message::PARSE);
-        InputBuffer buffer(recvbuf, cc);
-
-        try {
-            msg.fromWire(buffer);
-        } catch (...) {
-            cerr << "[AuthSrv] parse failed" << endl;
-            return;
-        }
-
-        cout << "[AuthSrv] received a message:\n" << msg.toText() << endl;
+    try {
+            message.fromWire(request_buffer);
+    } catch (...) {
+        cerr << "[AuthSrv] parse failed" << endl;
+        return (-1);
+    }
 
-        if (msg.getRRCount(Section::QUESTION()) != 1) {
-            return;
-        }
+    cout << "[AuthSrv] received a message:\n" << message.toText() << endl;
 
-        bool dnssec_ok = msg.isDNSSECSupported();
-        uint16_t remote_bufsize = msg.getUDPSize();
-
-        msg.makeResponse();
-        msg.setHeaderFlag(MessageFlag::AA());
-        msg.setRcode(Rcode::NOERROR());
-        msg.setDNSSECSupported(dnssec_ok);
-        msg.setUDPSize(sizeof(recvbuf));
-
-        Query query(msg, dnssec_ok);
-        impl_->data_sources.doQuery(query);
-
-        OutputBuffer obuffer(remote_bufsize);
-        MessageRenderer renderer(obuffer);
-        msg.toWire(renderer);
-        cout << "sending a response (" <<
-            boost::lexical_cast<string>(obuffer.getLength())
-                  << " bytes):\n" << msg.toText() << endl;
-        sendto(fd, obuffer.getData(), obuffer.getLength(), 0, sa, sa_len);
+    if (message.getRRCount(Section::QUESTION()) != 1) {
+        return (-1);
     }
+
+    bool dnssec_ok = message.isDNSSECSupported();
+    // unused for now.  should set this to renderer for truncation
+    uint16_t remote_bufsize = message.getUDPSize();
+
+    message.makeResponse();
+    message.setHeaderFlag(MessageFlag::AA());
+    message.setRcode(Rcode::NOERROR());
+    message.setDNSSECSupported(dnssec_ok);
+    message.setUDPSize(4096);   // XXX: hardcoding
+
+    Query query(message, dnssec_ok);
+    impl_->data_sources.doQuery(query);
+
+    message.toWire(response_renderer);
+    cout << "sending a response:\n" << message.toText() << endl;
+
+    return (0);
 }
 
 void

+ 11 - 1
src/bin/auth/auth_srv.h

@@ -21,6 +21,14 @@
 
 #include <cc/data.h>
 
+namespace isc {
+namespace dns {
+class InputBuffer;
+class Message;
+class MessageRenderer;
+}
+}
+
 class AuthSrvImpl;
 
 class AuthSrv {
@@ -37,7 +45,9 @@ public:
     explicit AuthSrv();
     ~AuthSrv();
     //@}
-    void processMessage(int fd);
+    int processMessage(isc::dns::InputBuffer& request_buffer,
+                       isc::dns::Message& message,
+                       isc::dns::MessageRenderer& response_renderer);
     void serve(std::string zone_name);
     void setDbFile(const std::string& db_file);
     isc::data::ElementPtr updateConfig(isc::data::ElementPtr config);

+ 253 - 93
src/bin/auth/main.cc

@@ -18,18 +18,21 @@
 #include <sys/socket.h>
 #include <sys/select.h>
 #include <netdb.h>
-#include <netinet/in.h>  // IPPROTO_UDP
 #include <stdlib.h>
 
 #include <set>
 #include <iostream>
 
 #include <boost/foreach.hpp>
+#include <boost/bind.hpp>
+#include <boost/asio.hpp>
 
 #include <dns/buffer.h>
 #include <dns/name.h>
+#include <dns/message.h>
 #include <dns/rrset.h>
 #include <dns/message.h>
+#include <dns/messagerenderer.h>
 
 #include <cc/session.h>
 #include <cc/data.h>
@@ -42,13 +45,19 @@
 #include <boost/foreach.hpp>
 
 using namespace std;
+
+using namespace boost::asio;
+using ip::udp;
+using ip::tcp;
+
 using namespace isc::data;
 using namespace isc::cc;
 using namespace isc::config;
+using namespace isc::dns;
 
 namespace {
 const string PROGRAM = "Auth";
-const char* DNSPORT = "5300";
+const short DNSPORT = 5300;
 }
 
 /* need global var for config/command handlers.
@@ -58,6 +67,213 @@ namespace {
 AuthSrv *auth_server;
 }
 
+//
+// Helper classes for asynchronous I/O using boost::asio
+//
+namespace {
+class Completed {
+public:
+    Completed(size_t len) : len_(len) {}
+    bool operator()(const boost::system::error_code& error,
+                    size_t bytes_transferred) const
+    {
+        return (error != 0 || bytes_transferred >= len_);
+    }
+private:
+    size_t len_;
+};
+
+class TCPClient {
+public:
+    TCPClient(io_service& io_service) :
+        socket_(io_service),
+        response_buffer_(0),
+        responselen_buffer_(TCP_MESSAGE_LENGTHSIZE),
+        response_renderer_(response_buffer_),
+        dns_message_(Message::PARSE)
+    {}
+
+    void start() {
+        async_read(socket_, boost::asio::buffer(data_, TCP_MESSAGE_LENGTHSIZE),
+                   Completed(TCP_MESSAGE_LENGTHSIZE),
+                   boost::bind(&TCPClient::headerRead, this,
+                               placeholders::error,
+                               placeholders::bytes_transferred));
+    }
+
+    tcp::socket& getSocket() { return (socket_); }
+
+    void headerRead(const boost::system::error_code& error,
+                    size_t bytes_transferred)
+    {
+        if (!error) {
+            assert(bytes_transferred == TCP_MESSAGE_LENGTHSIZE);
+            InputBuffer dnsbuffer(data_, TCP_MESSAGE_LENGTHSIZE);
+
+            uint16_t msglen = dnsbuffer.readUint16();
+            async_read(socket_, boost::asio::buffer(data_, msglen),
+                       Completed(msglen),
+                       boost::bind(&TCPClient::requestRead, this,
+                                   placeholders::error,
+                                   placeholders::bytes_transferred));
+        } else {
+            delete this;
+        }
+    }
+
+    void requestRead(const boost::system::error_code& error,
+                     size_t bytes_transferred)
+    {
+        if (!error) {
+            InputBuffer dnsbuffer(data_, bytes_transferred);
+            if (auth_server->processMessage(dnsbuffer, dns_message_,
+                                            response_renderer_) == 0) {
+                responselen_buffer_.writeUint16(response_buffer_.getLength());
+                async_write(socket_,
+                            boost::asio::buffer(
+                                responselen_buffer_.getData(),
+                                responselen_buffer_.getLength()),
+                        boost::bind(&TCPClient::responseWrite, this,
+                                    placeholders::error));
+            } else {
+                delete this;
+            }
+        } else {
+            delete this;
+        }
+    }
+
+    void responseWrite(const boost::system::error_code& error)
+    {
+        if (!error) {
+                async_write(socket_,
+                            boost::asio::buffer(response_buffer_.getData(),
+                                                response_buffer_.getLength()),
+                        boost::bind(&TCPClient::handleWrite, this,
+                                    placeholders::error));
+        }
+    }
+
+    void handleWrite(const boost::system::error_code& error)
+    {
+        if (!error) {
+            start();            // handle next request, if any.
+      } else {
+            delete this;
+      }
+    }
+
+private:
+    tcp::socket socket_;
+    OutputBuffer response_buffer_;
+    OutputBuffer responselen_buffer_;
+    MessageRenderer response_renderer_;
+    Message dns_message_;
+    enum { MAX_LENGTH = 65535 };
+    static const size_t TCP_MESSAGE_LENGTHSIZE = 2;
+    char data_[MAX_LENGTH];
+};
+
+class TCPServer
+{
+public:
+    TCPServer(io_service& io_service, int af, short port) :
+        io_service_(io_service),
+        acceptor_(io_service,
+                  tcp::endpoint(af == AF_INET6 ? tcp::v6() : tcp::v4(), port))
+    {
+        TCPClient* new_client = new TCPClient(io_service_);
+        // XXX: isn't the following exception free?  Need to check it.
+        acceptor_.async_accept(new_client->getSocket(),
+                               boost::bind(&TCPServer::handleAccept, this,
+                                           new_client, placeholders::error));
+    }
+
+    void handleAccept(TCPClient* new_client,
+                      const boost::system::error_code& error)
+    {
+        if (!error) {
+            new_client->start();
+            new_client = new TCPClient(io_service_);
+            acceptor_.async_accept(new_client->getSocket(),
+                                   boost::bind(&TCPServer::handleAccept,
+                                               this, new_client,
+                                               placeholders::error));
+        } else {
+            delete new_client;
+        }
+    }
+
+private:
+    io_service& io_service_;
+    tcp::acceptor acceptor_;
+};
+
+class UDPServer {
+public:
+    UDPServer(io_service& io_service, int af, short port) :
+        io_service_(io_service),
+        socket_(io_service,
+                udp::endpoint(af == AF_INET6 ? udp::v6() : udp::v4(), port)),
+        response_buffer_(0),
+        response_renderer_(response_buffer_),
+        dns_message_(Message::PARSE)
+    {
+        startReceive();
+    }
+
+    void handleRequest(const boost::system::error_code& error,
+                       size_t bytes_recvd)
+    {
+        if (!error && bytes_recvd > 0) {
+            InputBuffer request_buffer(data_, bytes_recvd);
+
+            dns_message_.clear(Message::PARSE);
+            response_renderer_.clear();
+            if (auth_server->processMessage(request_buffer, dns_message_,
+                                            response_renderer_) == 0) {
+                socket_.async_send_to(
+                    boost::asio::buffer(response_buffer_.getData(),
+                                        response_buffer_.getLength()),
+                    sender_endpoint_,
+                    boost::bind(&UDPServer::sendCompleted,
+                                this,
+                                placeholders::error,
+                                placeholders::bytes_transferred));
+            } else {
+                startReceive();
+            }
+        } else {
+            startReceive();
+        }
+    }
+
+    void sendCompleted(const boost::system::error_code& error,
+                       size_t bytes_sent)
+    {
+        startReceive();
+    }
+private:
+    void startReceive() {
+        socket_.async_receive_from(
+            boost::asio::buffer(data_, MAX_LENGTH), sender_endpoint_,
+            boost::bind(&UDPServer::handleRequest, this,
+                        placeholders::error,
+                        placeholders::bytes_transferred));
+    }
+
+private:
+    io_service& io_service_;
+    udp::socket socket_;
+    OutputBuffer response_buffer_;
+    MessageRenderer response_renderer_;
+    Message dns_message_;
+    udp::endpoint sender_endpoint_;
+    enum { MAX_LENGTH = 4096 };
+    char data_[MAX_LENGTH];
+};
+}
+
 static void
 usage() {
     cerr << "Usage: b10-auth [-p port] [-4|-6]" << endl;
@@ -85,50 +301,16 @@ my_command_handler(const string& command, const ElementPtr args) {
     return answer;
 }
 
-static int
-getSocket(int af, const char* port) {
-    struct addrinfo hints, *res;
-
-    memset(&hints, 0, sizeof(hints));
-    hints.ai_family = af;
-    hints.ai_socktype = SOCK_DGRAM;
-    hints.ai_flags = AI_PASSIVE;
-    hints.ai_protocol = IPPROTO_UDP;
-
-    int error = getaddrinfo(NULL, port, &hints, &res);
-    if (error != 0) {
-        cerr << "getaddrinfo failed: " << gai_strerror(error);
-        return (-1);
-    }
-
-    int s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
-    if (s < 0) {
-        cerr << "failed to open socket" << endl;
-        return (-1);
-    }
-
-    if (af == AF_INET6) {
-        int on = 1;
-        if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
-            cerr << "couldn't set IPV6_V6ONLY socket option" << endl;
-        }
-    }
-
-    if (bind(s, res->ai_addr, res->ai_addrlen) < 0) {
-        cerr << "binding socket failure" << endl;
-        close(s);
-        return (-1);
-    }
-
-    return (s);
-}
-
 int
 main(int argc, char* argv[]) {
     int ch;
-    const char* port = DNSPORT;
+    short port = DNSPORT;
     bool ipv4_only = false, ipv6_only = false;
-    int ps4 = -1, ps6 = -1;
+    bool use_ipv4 = false, use_ipv6 = false;
+    UDPServer* udp4_server = NULL;
+    UDPServer* udp6_server = NULL;
+    TCPServer* tcp4_server = NULL;
+    TCPServer* tcp6_server = NULL;
 
     while ((ch = getopt(argc, argv, "46p:")) != -1) {
         switch (ch) {
@@ -139,7 +321,7 @@ main(int argc, char* argv[]) {
             ipv6_only = true;
             break;
         case 'p':
-            port = optarg;
+            port = atoi(optarg);
             break;
         case '?':
         default:
@@ -156,19 +338,10 @@ main(int argc, char* argv[]) {
         usage();
     }
     if (!ipv6_only) {
-        ps4 = getSocket(AF_INET, port);
-        if (ps4 < 0) {
-            exit(1);
-        }
+        use_ipv4 = true;
     }
     if (!ipv4_only) {
-        ps6 = getSocket(AF_INET6, port);
-        if (ps6 < 0) {
-            if (ps4 < 0) {
-                close(ps4);
-            }
-            exit(1);
-        }
+        use_ipv4 = true;
     }
 
     auth_server = new AuthSrv;
@@ -186,52 +359,39 @@ main(int argc, char* argv[]) {
         ModuleCCSession cs = ModuleCCSession(specfile, my_config_handler,
                                              my_command_handler);
 
-        // main server loop
-        fd_set fds;
-        int ss = cs.getSocket();
-        int nfds = max(max(ps4, ps6), ss) + 1;
-        int counter = 0;
+        // XXX: in this prototype code we'll ignore any message on the command
+        // channel.
 
-        cout << "Server started." << endl;
-        while (true) {
-            FD_ZERO(&fds);
-            if (ps4 >= 0) {
-                FD_SET(ps4, &fds);
-            }
-            if (ps6 >= 0) {
-                FD_SET(ps6, &fds);
-            }
-            FD_SET(ss, &fds);
-
-            int n = select(nfds, &fds, NULL, NULL, NULL);
-            if (n < 0) {
-                throw FatalError("select error");
-            }
-
-            if (ps4 >= 0 && FD_ISSET(ps4, &fds)) {
-                ++counter;
-                auth_server->processMessage(ps4);
-            }
-            if (ps6 >= 0 && FD_ISSET(ps6, &fds)) {
-                ++counter;
-                auth_server->processMessage(ps6);
-            }
-    
-            if (FD_ISSET(ss, &fds)) {
-                cs.check_command();
-            }
+        boost::asio::io_service io_service;
+        if (use_ipv4) {
+            udp4_server = new UDPServer(io_service, AF_INET, port);
+            tcp4_server = new TCPServer(io_service, AF_INET, port);
+        }
+        if (use_ipv6) {
+            udp6_server = new UDPServer(io_service, AF_INET6, port);
+            tcp6_server = new TCPServer(io_service, AF_INET6, port);
         }
-    } catch (SessionError se) {
-        cout << se.what() << endl;
+
+        cout << "Server started." << endl;
+        io_service.run();
+    } catch (const std::exception& ex) {
+        cerr << ex.what() << endl;
         ret = 1;
     }
 
-    if (ps4 >= 0) {
-        close(ps4);
+    if (udp4_server != NULL) {
+        delete udp4_server;
+    }
+    if (tcp4_server != NULL) {
+        delete tcp4_server;
     }
-    if (ps6 >= 0) {
-        close(ps6);
+    if (udp6_server != NULL) {
+        delete udp6_server;
     }
+    if (tcp6_server != NULL) {
+        delete tcp6_server;
+    }
+
     delete auth_server;
     return (ret);
 }

+ 2 - 1
src/lib/dns/message.cc

@@ -761,9 +761,10 @@ Message::toText() const
 }
 
 void
-Message::clear()
+Message::clear(Mode mode)
 {
     impl_->init();
+    impl_->mode_ = mode;
 }
 
 void

+ 1 - 1
src/lib/dns/message.h

@@ -563,7 +563,7 @@ public:
     //void addRR(const Section& section, const RR& rr);
     //void removeRR(const Section& section, const RR& rr);
 
-    void clear();
+    void clear(Mode mode);
 
     // prepare for making a response from a request.  This will clear the
     // DNS header except those fields that should be kept for the response,

+ 9 - 9
src/lib/dns/tests/message_unittest.cc

@@ -124,12 +124,12 @@ TEST_F(MessageTest, GetEDNS0DOBit)
     EXPECT_FALSE(message_parse.isDNSSECSupported());
 
     // If DO bit is on, DNSSEC is considered to be supported.
-    message_parse.clear();
+    message_parse.clear(Message::PARSE);
     factoryFromFile(message_parse, "testdata/message_fromWire2");
     EXPECT_TRUE(message_parse.isDNSSECSupported());
 
     // If DO bit is off, DNSSEC is considered to be unsupported.
-    message_parse.clear();
+    message_parse.clear(Message::PARSE);
     factoryFromFile(message_parse, "testdata/message_fromWire3");
     EXPECT_FALSE(message_parse.isDNSSECSupported());
 }
@@ -162,12 +162,12 @@ TEST_F(MessageTest, GetEDNS0UDPSize)
     EXPECT_EQ(Message::DEFAULT_MAX_UDPSIZE, message_parse.getUDPSize());
 
     // If the size specified in EDNS0 > default max, use it.
-    message_parse.clear();
+    message_parse.clear(Message::PARSE);
     factoryFromFile(message_parse, "testdata/message_fromWire2");
     EXPECT_EQ(4096, message_parse.getUDPSize());
 
     // If the size specified in EDNS0 < default max, keep using the default.
-    message_parse.clear();
+    message_parse.clear(Message::PARSE);
     factoryFromFile(message_parse, "testdata/message_fromWire8");
     EXPECT_EQ(Message::DEFAULT_MAX_UDPSIZE, message_parse.getUDPSize());
 }
@@ -203,7 +203,7 @@ TEST_F(MessageTest, EDNS0ExtCode)
     EXPECT_EQ(Rcode::BADVERS(), message_parse.getRcode());
 
     // Maximum extended Rcode
-    message_parse.clear();
+    message_parse.clear(Message::PARSE);
     factoryFromFile(message_parse, "testdata/message_fromWire11");
     EXPECT_EQ(0xfff, message_parse.getRcode().getCode());
 }
@@ -214,21 +214,21 @@ TEST_F(MessageTest, BadEDNS0)
     EXPECT_THROW(factoryFromFile(message_parse, "testdata/message_fromWire4"),
                  DNSMessageFORMERR);
     // multiple OPT RRs (in the additional section)
-    message_parse.clear();
+    message_parse.clear(Message::PARSE);
     EXPECT_THROW(factoryFromFile(message_parse, "testdata/message_fromWire5"),
                  DNSMessageFORMERR);
     // OPT RR of a non root name
-    message_parse.clear();
+    message_parse.clear(Message::PARSE);
     EXPECT_THROW(factoryFromFile(message_parse, "testdata/message_fromWire6"),
                  DNSMessageFORMERR);
     // Compressed owner name of OPT RR points to a root name.
     // Not necessarily bogus, but very unusual and mostly pathological.
     // We accept it, but is it okay?
-    message_parse.clear();
+    message_parse.clear(Message::PARSE);
     EXPECT_NO_THROW(factoryFromFile(message_parse,
                                     "testdata/message_fromWire7"));
     // Unsupported Version
-    message_parse.clear();
+    message_parse.clear(Message::PARSE);
     EXPECT_THROW(factoryFromFile(message_parse, "testdata/message_fromWire9"),
                  DNSMessageBADVERS);
 }