Using the boost-net-dns library to resolve DNS host names
authorGuilherme Maciel Ferreira <guilherme.maciel.ferreira@intra2net.com>
Fri, 15 Apr 2011 11:04:13 +0000 (13:04 +0200)
committerGuilherme Maciel Ferreira <guilherme.maciel.ferreira@intra2net.com>
Fri, 15 Apr 2011 12:07:36 +0000 (14:07 +0200)
15 files changed:
.gitignore
lib/boost-net-dns/boost/net/basic_dns_resolver.hpp [new file with mode: 0755]
lib/boost-net-dns/boost/net/basic_dns_resolver_service.hpp [new file with mode: 0755]
lib/boost-net-dns/boost/net/dns.hpp [new file with mode: 0755]
lib/boost-net-dns/boost/net/dns_cache.hpp [new file with mode: 0755]
lib/boost-net-dns/boost/net/dns_debug.hpp [new file with mode: 0755]
lib/boost-net-dns/boost/net/dns_resolver.hpp [new file with mode: 0755]
lib/boost-net-dns/boost/net/impl/dns_resolver_impl.hpp [new file with mode: 0755]
lib/boost-net-dns/boost/net/network_array.hpp [new file with mode: 0755]
lib/boost-net-dns/boost/net/resolve.hpp [new file with mode: 0755]
lib/boost-net-dns/boost/net/rfc1035_414.hpp [new file with mode: 0755]
src/CMakeLists.txt
src/dns/dnsresolver.cpp
src/dns/hostaddress.cpp
src/dns/hostaddress.h

index f04e513..3fea642 100644 (file)
@@ -9,3 +9,7 @@ Debug
 
 # uml cache files
 *.vpp~*
+
+# version control (CVS, SVN, GIT)
+.cvs
+.svn
diff --git a/lib/boost-net-dns/boost/net/basic_dns_resolver.hpp b/lib/boost-net-dns/boost/net/basic_dns_resolver.hpp
new file mode 100755 (executable)
index 0000000..50a7fbf
--- /dev/null
@@ -0,0 +1,62 @@
+//
+// basic_dns_resolver.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2008 Andreas Haberstroh (andreas at ibusy dot com)
+//
+// 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_NET_BASIC_DNS_RESOLVER_HPP
+#define BOOST_NET_BASIC_DNS_RESOLVER_HPP
+
+namespace boost {
+  namespace net {
+    namespace dns {
+
+      template <typename Service> \r
+      class basic_dns_resolver : public boost::asio::basic_io_object<Service> \r
+      { \r
+      public: \r
+        explicit basic_dns_resolver(boost::asio::io_service &io_service) \r
+        : boost::asio::basic_io_object<Service>(io_service) \r
+        { \r
+        } 
+
+        void add_nameserver(ip::address addr)
+        {
+          this->service.add_nameserver(this->implementation, addr);
+        }
+
+        template<typename CallbackHandler>
+        void async_resolve(const net::dns::question & question, CallbackHandler handler)
+        {
+          this->service.async_resolve(this->implementation, question, handler);
+        }
+          
+        template<typename CallbackHandler>
+        void async_resolve(const string & domain, const net::dns::type_t rrtype, CallbackHandler handler)
+        {
+          this->service.async_resolve(this->implementation, domain, rrtype, handler);
+        }
+
+        rr_list_t resolve(const net::dns::question & question)
+        {
+          return this->service.resolve(this->implementation, question);
+        }
+
+        rr_list_t resolve(const string & domain, const net::dns::type_t rrtype)
+        {
+          return this->service.resolve(this->implementation, domain, rrtype);
+        }
+      }; 
+
+#if !defined(GENERATING_DOCUMENTATION)
+      typedef basic_dns_resolver<basic_dns_resolver_service<> > dns_resolver; 
+#endif
+
+    } // namespace dns
+  }   // namespace net
+}     // namespace boost
+
+#endif // BOOST_NET_BASIC_DNS_RESOLVER_HPP
diff --git a/lib/boost-net-dns/boost/net/basic_dns_resolver_service.hpp b/lib/boost-net-dns/boost/net/basic_dns_resolver_service.hpp
new file mode 100755 (executable)
index 0000000..ecd873e
--- /dev/null
@@ -0,0 +1,98 @@
+//
+// basic_dns_resolver_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2008 Andreas Haberstroh (andreas at ibusy dot com)
+//
+// 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_NET_BASIC_DNS_RESOLVER_SERVICE_HPP
+#define BOOST_NET_BASIC_DNS_RESOLVER_SERVICE_HPP
+
+#include <boost/net/dns.hpp>
+#include <boost/thread/thread.hpp>
+
+namespace boost {
+  namespace net {
+    namespace dns {
+  
+      template <typename DnsResolverImplementation = dns_resolver_impl> \r
+      class basic_dns_resolver_service : public boost::asio::io_service::service \r
+      { \r
+      public: \r
+        static boost::asio::io_service::id id; \r
+\r
+        explicit basic_dns_resolver_service(boost::asio::io_service &io_service) \r
+        : boost::asio::io_service::service(io_service), 
+          work_(new boost::asio::io_service::work(work_io_service_)), \r
+          work_thread_(boost::bind(&boost::asio::io_service::run, &work_io_service_)) \r
+        { \r
+        } \r
+\r
+        virtual ~basic_dns_resolver_service() \r
+        { 
+          work_.reset(); \r
+          work_io_service_.stop(); \r
+          work_thread_.join(); \r
+        } \r
+\r
+        typedef boost::shared_ptr<DnsResolverImplementation> implementation_type; \r
+\r
+        void construct(implementation_type &impl) \r
+        { \r
+          impl.reset(new DnsResolverImplementation(this->get_io_service())); \r
+        } \r
+\r
+        void destroy(implementation_type &impl) \r
+        { \r
+          impl->destroy(); \r
+          impl.reset(); \r
+        } 
+
+        rr_list_t resolve(implementation_type &impl, const net::dns::question & question)
+        {
+          return impl->resolve(question);
+        }
+
+        rr_list_t resolve(implementation_type &impl, const string & domain, const net::dns::type_t rrtype)
+        {
+          return impl->resolve(domain, rrtype);
+        }
+        
+        template<typename CallbackHandler>
+        void async_resolve(implementation_type &impl, const net::dns::question & question, CallbackHandler handler)
+        {
+          impl->async_resolve(question, handler);
+        }
+          
+        template<typename CallbackHandler>
+        void async_resolve(implementation_type &impl, const string & domain, const net::dns::type_t rrtype, CallbackHandler handler)
+        {
+          net::dns::question question(domain, rrtype);
+          impl->async_resolve(question, handler);
+        }
+
+        void add_nameserver(implementation_type &impl, ip::address addr)
+        {
+          impl->add_nameserver(addr);
+        }
+\r
+      private: \r
+        void shutdown_service() \r
+        { \r
+        } \r
+\r
+        boost::asio::io_service work_io_service_; \r
+        boost::scoped_ptr<boost::asio::io_service::work> work_; \r
+        boost::thread work_thread_; \r
+      }; \r
+#if !defined(GENERATING_DOCUMENTATION)
+      template <typename DnsResolverImplementation> \r
+      boost::asio::io_service::id basic_dns_resolver_service<DnsResolverImplementation>::id; \r
+#endif
+    } // namespace dns
+  }   // namespace net
+}     // namespace boost
+
+#endif // BOOST_NET_BASIC_DNS_RESOLVER_SERVICE_HPP
diff --git a/lib/boost-net-dns/boost/net/dns.hpp b/lib/boost-net-dns/boost/net/dns.hpp
new file mode 100755 (executable)
index 0000000..510f61e
--- /dev/null
@@ -0,0 +1,2622 @@
+//
+// dns.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 1998-2008 Andreas Haberstroh (andreas at ibusy dot com)
+//
+// 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_NET_DNS_HPP
+#define BOOST_NET_DNS_HPP
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <vector>
+#include <string>
+
+#include <boost/asio.hpp>
+#include <boost/net/network_array.hpp>
+#include <boost/net/rfc1035_414.hpp>
+
+using namespace std;
+using namespace boost;
+using namespace boost::algorithm;
+
+namespace boost {
+  namespace net {
+    namespace dns {
+
+// quick forward declarations
+class message;
+class request_base_t;
+class resource_base_t;
+
+//! Shared Resource Base Pointer
+typedef shared_ptr<resource_base_t>         shared_resource_base_t;
+
+//! A list of resource records
+typedef std::vector<shared_resource_base_t> rr_list_t;
+
+//! A shared list of resource records
+typedef shared_ptr<rr_list_t>               shared_rr_list_t;
+
+//! Shared Request Base Pointer
+typedef shared_ptr<request_base_t>          shared_request_base_t;
+
+//! Class identification for resource records. Included is the QCLASS that is in the 0xF0 range.
+typedef enum
+{
+  class_none = 0x00,  //!< No class definition
+  class_in,           //!< Internet class. Default class
+       class_cs,           //!< CSNET class, obsolete, used for examples.
+  class_ch,           //!< CHAOS class
+  class_hs,           //!< Hesiod [Dyer 87]
+       class_all = 0xff    //!< Query all classes
+} class_t;
+
+//! Type identification for resource records. Included are the QTYPE's that are in the 0xF0 range
+typedef enum
+{
+  type_none  = 0x00,  //!< No type definition.
+  type_a     = 0x01,  //!< Address type
+  type_ns    = 0x02,  //!< Name Server type
+  type_cname = 0x05,  //!< Canonical name type
+  type_soa   = 0x06,  //!< Start of Authority type
+  type_ptr   = 0x0c,  //!< Pointer type
+  type_hinfo = 0x0d,  //!< Host Information type
+  type_mx    = 0x0f,  //!< Mail Exchanger type
+  type_txt   = 0x10,  //!< Text type
+  type_a6    = 0x1c,  //!< Address (IP6) type
+  type_srv   = 0x21,  //!< Service type
+  type_axfr  = 0xfc,  //!< Zone transfer type
+  type_all   = 0xff   //!< Query all types
+} type_t;
+
+
+/*!
+Basic definition of a DNS request.
+
+Shared by Questions and all the different resource record types
+*/
+class request_base_t
+{
+protected:
+  /// Domain name of the resource record
+  string    rr_domain;
+
+  /// Resource record type
+  uint16_t  rr_type;
+
+  /// Resource record class
+  uint16_t  rr_class;
+
+public:
+  /// Default constructor
+  request_base_t()
+    : rr_domain(),
+      rr_type(type_none),
+      rr_class(class_none)
+  {}
+
+  /*!
+  Copy contructor
+
+  \param o request_base_t to copy
+  */
+  request_base_t(const request_base_t & o)
+    : rr_domain(o.rr_domain),
+      rr_type(o.rr_type),
+      rr_class(o.rr_class)
+  {
+  }
+
+  /*!
+  Constructs a request_base_t
+
+  \param t Resource type to create object for
+  \param c Resource class to create object for
+  */
+  request_base_t(const type_t t, const class_t c=class_in)
+    : rr_domain(),
+      rr_type(t),
+      rr_class(c)
+  {
+  }
+
+  /*!
+  Constructs a request_base_t
+
+  \param d Domain name to create object for
+  \param t Resource type to create object for
+  \param c Resource class to create object for
+  */
+  request_base_t(const string & d, const type_t t, const class_t c=class_in)
+    : rr_domain(d),
+      rr_type(t),
+      rr_class(c)
+  {}
+
+  /*!
+  Constructor that creates the request_base_t from a network buffer
+
+  \param buffer Memory buffer to read from
+  \param offset_map DNS label compression map for label/offset values
+  */
+  request_base_t(dns_buffer_t& buffer, rfc1035_414_t& offset_map)
+    : rr_domain(),
+      rr_type(),
+      rr_class()
+  {
+    decode(buffer, offset_map);
+  }
+
+  /// Virtual Destructor
+  virtual ~request_base_t()
+  {
+  }
+
+  /*!
+  Sets the domain name
+
+  \param s Domain name to assign to the request_base_t
+  \return current domain name
+  */
+       const string& domain(const string& s)
+  {
+    return domain(s.c_str());
+  }
+
+  /*!
+  Sets the domain name
+
+  \param s Domain name to assign to the request_base_t.
+  \return current domain name
+  */
+  const string& domain(const char* s)
+  {
+    rr_domain = s;
+    return rr_domain;
+  }
+
+  /*!
+  Gets the domain name
+
+  \return current domain name
+  */
+  const string& domain() const
+  {
+    return rr_domain;
+  }
+
+
+  /*!
+  Sets the resource record type
+
+  \param t resource type to assign to the request_base_t.
+  \return Current type
+  */
+  type_t  rtype(const type_t t)
+  {
+    rr_type = t;
+    return (type_t)rr_type;
+  }
+
+  /*!
+  Gets the resource record type
+
+  \return Current type
+  */
+  type_t  rtype() const
+  {
+    return (type_t)rr_type;
+  }
+
+  /*!
+  Sets the resource record class
+
+  \param c resource class to assign to the request_base_t.
+  \return current class
+  */
+  class_t  rclass(const class_t c)
+  {
+    rr_class = c;
+    return (class_t)rr_class;
+  }
+
+  /*!
+  Gets the resource record class
+
+  \return current class
+  */
+  class_t  rclass() const
+  {
+    return (class_t)rr_class;
+  }
+
+  /// Friend to tie to the containers in the message class.
+  friend class message;
+
+protected:
+  /*!
+  Encodes the request_base_t into a memory buffer
+
+  \param buffer Buffer to encode the request into
+  \param offset_map DNS label compression map for label/offset values
+  */
+  void encode(dns_buffer_t& buffer, rfc1035_414_t& offset_map)
+  {
+    offset_map.write_label(rr_domain, buffer);
+    BOOST_ASSERT( rr_type != 0x0000 );
+    buffer.put( rr_type );
+    BOOST_ASSERT( rr_class != 0x0000 );
+    buffer.put( rr_class );
+  }
+
+  /*!
+  Decodes the request_base_t into a memory buffer
+
+  \param buffer Buffer to decode the request into
+  \param offset_map DNS label compression map for label/offset values
+  */
+  void decode(dns_buffer_t& buffer, rfc1035_414_t& offset_map)
+  {
+    offset_map.read_label(rr_domain, buffer);
+    buffer.get( rr_type );
+    buffer.get( rr_class );
+  }
+};
+
+/// A question is a simple thing
+class question : public request_base_t
+{
+public:
+  /// Default constructor
+  question()
+  : request_base_t()
+  {}
+
+  /*!
+  Copy contructor
+
+  \param o question to copy
+  */
+  question(const request_base_t & o)
+  : request_base_t(o)
+  {
+  }
+
+  /*!
+  Copy contructor
+
+  \param o question to copy
+  */
+  question(const question & o)
+  : request_base_t()
+  {
+    domain(o.domain());
+    rtype(o.rtype());
+    rclass(o.rclass());
+  }
+
+  /*!
+  Constructs a question
+
+  \param t Resource type to create object for
+  \param c Resource class to create object for
+  */
+  question(const type_t t, const class_t c=class_in)
+    : request_base_t(t, c)
+  {
+  }
+
+  /*!
+  Constructs a question
+
+  \param d Domain name to create object for
+  \param t Resource type to create object for
+  \param c Resource class to create object for
+  */
+  question(const string & d, const type_t t, const class_t c=class_in)
+    : request_base_t(d, t, c)
+  {}
+
+  /*!
+  Constructor that creates the question from a network buffer
+
+  \param buffer Memory buffer to read from
+  \param offset_map DNS label compression map for label/offset values
+  */
+  question(dns_buffer_t& buffer, rfc1035_414_t& offset_map)
+  : request_base_t(buffer, offset_map)
+  {
+  }
+
+  /// Virtual Destructor
+  virtual ~question()
+  {
+  }
+};
+
+/*!
+Basic definition of a DNS resource record.
+
+*/
+class  resource_base_t : public request_base_t
+{
+private:
+  /// Time To Live value for the resource record
+  uint32_t  rr_ttl;
+
+  /// Resource Record payload length
+  uint16_t  rr_length;
+
+public:
+  /// Constructs an empty resource_base_t
+  resource_base_t()
+    : request_base_t(),
+      rr_ttl(0),
+      rr_length(0)
+  {}
+
+  /*!
+  Copy contructor
+
+  \param o resource_base_t to copy
+  */
+  resource_base_t(const resource_base_t& o)
+    : request_base_t(o),
+      rr_ttl(o.rr_ttl),
+      rr_length(o.rr_length)
+  {}
+
+  /*!
+  Sets the resource type and defaults the resource class to class_in.
+
+  \param t Resource type to create object for
+  */
+  resource_base_t(const type_t t)
+    : request_base_t(t,class_in),
+      rr_ttl(0),
+      rr_length(0)
+  {}
+
+  /*!
+  Defaults the resource class to class_in.
+
+  \param s Domain name to create object for
+  \param t Resource type to create object for
+  */
+  resource_base_t(const string& s, const type_t t)
+    : request_base_t(s,t,class_in),
+      rr_ttl(0),
+      rr_length(0)
+  {}
+
+  /*!
+  Constructor that creates the resource_base_t from a memory buffer
+
+  \param buffer Memory buffer to read from
+  \param offset_map
+  */
+  resource_base_t(dns_buffer_t& buffer, rfc1035_414_t& offset_map)
+    : rr_ttl(0),
+      rr_length(0)
+  {
+    decode(buffer, offset_map);
+  }
+
+  virtual ~resource_base_t()
+  {
+  }
+
+  /*!
+  Clones an existing resource record object
+  */
+  virtual shared_resource_base_t clone() const
+  {
+    return shared_resource_base_t(new resource_base_t(*this));
+  }
+
+  /*!
+  Sets the Time To Live value
+
+  \param t Time to Live to assign to the resource_base_t.
+  \return TTL value
+  */
+  uint32_t  ttl(const uint32_t t)
+  {
+    rr_ttl = t;
+    return rr_ttl;
+  }
+
+  /*!
+  Gets the Time To Live value
+
+  \return TTL value
+  */
+  uint32_t ttl() const
+  {
+    return rr_ttl;
+  }
+
+  /*!
+  Sets the payload length of the resource record
+
+  \param t Payload length to assign to the resource_base_t.
+  \return payload length
+  */
+  uint16_t  length(const uint16_t t)
+  {
+    rr_length = t;
+    return rr_length;
+  }
+
+  /*!
+  Gets the payload length of the resource record
+
+  \return payload length
+  */
+  uint16_t  length() const
+  {
+    return rr_length;
+  }
+
+  /// Friend to tie to the containers in the message class.
+  friend class message;
+
+protected:
+  /*!
+  Encodes the resource_base_t into a memory buffer
+
+  \param buffer Buffer to encode the request into
+  \param offset_map DNS label compression map for label/offset values
+  */
+  virtual void encode(dns_buffer_t& buffer, rfc1035_414_t& offset_map)
+  {
+    request_base_t::encode(buffer, offset_map);
+    buffer.put( rr_ttl );
+    buffer.put( rr_length );
+  }
+
+  /*!
+  Decodes the resource_base_t from a memory buffer
+
+  \param buffer Buffer to decode the request into
+  \param offset_map DNS label compression map for label/offset values
+  */
+  virtual void decode(dns_buffer_t& buffer, rfc1035_414_t& offset_map)
+  {
+    request_base_t::decode(buffer, offset_map);
+    buffer.get( rr_ttl );
+    buffer.get( rr_length );
+  }
+};
+
+/*!
+  Definition for an unknown resource
+
+  The RFC states that DNS cache servers should handle unknown RR types and simply pass them on as requested.
+  For instance, the original RFC didn't specify SRV records. And, many servers couldn't handle those types.
+  So, this class has an "unknown" type and simply passes unknown RRR types along as needed.
+*/
+class unknown_resource : public resource_base_t
+{
+protected:
+  /// Raw data for the unknown resource records.
+  shared_ptr<uint8_t> _data;
+
+public:
+  /// Default contructor
+  unknown_resource() : resource_base_t(), _data() {;}
+
+  /*!
+  Copy Constructor
+
+  \param o unknown resource to copy from
+  */
+  unknown_resource(const unknown_resource& o)
+  : resource_base_t(o),
+    _data( new uint8_t[length()] )
+  {
+    memcpy( _data.get(), o._data.get(), length() );
+  }
+
+  /*!
+  Copy Constructor
+
+  \param o resource_base_t to copy from
+  */
+  unknown_resource(const resource_base_t& o)
+  : resource_base_t(o),
+    _data()
+  {
+      ;
+  }
+
+  /// Virtual Destructor
+  virtual ~unknown_resource()
+  {
+  }
+
+  /*!
+  Clones an existing resource record object
+  */
+  virtual shared_resource_base_t clone() const
+  {
+    return shared_resource_base_t(new unknown_resource(*this));
+  }
+
+  /// Friend to tie to the containers in the message class.
+  friend class message;
+
+protected:
+  /*!
+  Encodes the a resource into a memory buffer
+
+  \param buffer Buffer to encode the request into
+  \param offset_map DNS label compression map for label/offset values
+  */
+  virtual void encode(dns_buffer_t& buffer, rfc1035_414_t& offset_map)
+  {
+    resource_base_t::encode(buffer, offset_map);
+
+    for( size_t i = 0; i < length(); ++i )
+      buffer.put( _data.get()[i] );
+  }
+
+  /*!
+  Decodes the a resource into a memory buffer
+
+  \param buffer Buffer to decode the request into
+  \param offset_map DNS label compression map for label/offset values
+  */
+  virtual void decode(dns_buffer_t& buffer, rfc1035_414_t& /*offset_map*/)
+  {
+    _data = shared_ptr<uint8_t>( new uint8_t[length()] );
+    for( size_t i = 0; i < length(); ++i )
+      buffer.get( _data.get()[i] );
+  }
+};
+
+/*!
+Definition for an A resource record
+*/
+class a_resource : public resource_base_t
+{
+protected:
+  /// IP 4 address
+  ip::address_v4 rr_address;
+
+public:
+  /// Default contructor
+  a_resource() : resource_base_t(type_a), rr_address(0)  {;}
+
+  /*!
+  Constructs a a_resource
+
+  \param s Host name for the A record
+  */
+  a_resource(const string& s) : resource_base_t(s, type_a), rr_address(0)  {;}
+
+  /// Virtual Destructor
+  virtual ~a_resource()
+  {
+  }
+
+  /*!
+  Sets the IP4 address from a ip::address_v4
+
+  \param addr Address to assign to the a_resource.
+  \return Address
+  */
+       const ip::address_v4& address(const ip::address_v4& addr)
+  {
+    rr_address = addr;
+    return rr_address;
+  }
+
+  /*!
+  Sets the IP4 address from a dotted decimal string
+
+  \param s Address to assign to the a_resource.
+  \return Address
+  */
+  const ip::address_v4& address(const char* s)
+  {
+    return address(ip::address_v4::from_string(s));
+  }
+
+  /*!
+  Gets the IP4 address
+
+  \return Address
+  */
+  const ip::address_v4& address() const
+  {
+    return rr_address;
+  }
+
+  /*!
+  Clones an existing resource record object
+  */
+  virtual shared_resource_base_t clone() const
+  {
+    return shared_resource_base_t(new a_resource(*this));
+  }
+
+  /// Friend to tie to the containers in the message class.
+  friend class message;
+
+protected:
+  /*!
+  Copy Constructor
+
+  \param o a_resource to copy from
+  */
+  a_resource(const a_resource& o) : resource_base_t(o), rr_address(o.rr_address) { ; }
+
+  /*!
+  Copy Constructor
+
+  \param o resource_base_t to copy from
+  */
+  a_resource(const resource_base_t& o) : resource_base_t(o), rr_address(0)  { ; }
+
+
+  /*!
+  Encodes the a resource into a memory buffer
+
+  \param buffer Buffer to encode the request into
+  \param offset_map DNS label compression map for label/offset values
+  */
+  virtual void encode(dns_buffer_t& buffer, rfc1035_414_t& offset_map)
+  {
+    resource_base_t::encode(buffer, offset_map);
+
+    // the length offset for the resource record
+    size_t lenOffset( buffer.position() - sizeof(uint16_t) );
+
+    size_t len(0);
+
+    len = buffer.put( rr_address );
+
+    // lastly, update the length field
+    buffer.put( (uint16_t)len, lenOffset, false );
+  }
+
+  /*
+  Decodes the a resource into a memory buffer
+
+  \param buffer Buffer to decode the request into
+  \param offset_map DNS label compression map for label/offset values
+  */
+  virtual void decode(dns_buffer_t& buffer, rfc1035_414_t& /*offset_map*/)
+  {
+    buffer.get(rr_address);
+  }
+};
+
+/*!
+Definition for an NS resource record
+
+*/
+class ns_resource : public resource_base_t
+{
+protected:
+  /// name server name
+  string       rr_nsdname;
+
+public:
+  /// Default contructor
+  ns_resource() : resource_base_t(type_ns), rr_nsdname() {;}
+
+  /*!
+  Constructs a ns_resource from a string
+
+  \param s Host name for the NS record
+  */
+  ns_resource(const string& s) : resource_base_t(s, type_ns), rr_nsdname(s) {;}
+
+  /// Virtual Destructor
+  virtual ~ns_resource()
+  {
+  }
+
+  /*!
+  Sets the nameserver from a string
+
+  \param s Nameserver to assign to the ns_resource.
+  \return Nameserver
+  */
+       const string& nameserver(const string& s)
+  {
+    return nameserver(s.c_str());
+  }
+
+  /*!
+  Sets the nameserver from a null-terminated C tring
+
+  \param s Nameserver string to assign to the ns_resource.
+  \return Nameserver
+  */
+  const string& nameserver(const char* s)
+  {
+    rr_nsdname = s;
+    return rr_nsdname;
+  }
+
+  /*!
+  Sets the nameserver
+
+  \return Nameserver
+  */
+  const string& nameserver() const
+  {
+    return rr_nsdname;
+  }
+
+  /*!
+  Clones an existing resource record object
+  */
+  virtual shared_resource_base_t clone() const
+  {
+    return shared_resource_base_t(new ns_resource(*this));
+  }
+
+  /// Friend to tie to the containers in the message class.
+  friend class message;
+
+protected:
+  /*!
+  Copy Constructor
+
+  \param o ns_resource to copy from
+  */
+  ns_resource(const ns_resource& o) : resource_base_t(o), rr_nsdname(o.rr_nsdname) { ; }
+
+  /*!
+  Copy Constructor
+
+  \param o resource_base_t to copy from
+  */
+  ns_resource(const resource_base_t& o)
+  : resource_base_t(o),
+    rr_nsdname()
+  {
+  }
+
+  /*!
+  Encodes the ns resource into a memory buffer
+
+  \param buffer Buffer to encode the request into
+  \param offset_map DNS label compression map for label/offset values
+  */
+  virtual void encode(dns_buffer_t& buffer, rfc1035_414_t& offset_map)
+  {
+    resource_base_t::encode(buffer, offset_map);
+
+    size_t lenOffset( buffer.position() - sizeof(uint16_t) );
+    size_t len = offset_map.write_label(rr_nsdname, buffer);
+
+    // lastly, update the length field
+    buffer.put( (uint16_t)len, lenOffset, false );
+  }
+
+  /*!
+  Decodes the ns resource into a memory buffer
+
+  \param buffer Buffer to decode the request into
+  \param offset_map DNS label compression map for label/offset values
+  */
+  virtual void decode(dns_buffer_t& buffer, rfc1035_414_t& offset_map)
+  {
+    offset_map.read_label(rr_nsdname, buffer);
+  }
+};
+
+/*!
+Definition of a CNAME resource
+*/
+class cname_resource : public resource_base_t
+{
+protected:
+  /// Canonical Name
+  string  rr_cname;
+
+public:
+  /// Default contructor
+  cname_resource() : resource_base_t(type_cname), rr_cname() {;}
+
+  /*!
+  Constructs a cname_resource
+
+  \param s Host name for the CNAME record
+  */
+  cname_resource(const string& s) : resource_base_t(s, type_cname), rr_cname(s) {;}
+
+  /// Virtual Destructor
+  virtual ~cname_resource()
+  {
+  }
+
+  /*!
+  Sets the Canonical name
+
+  \param s Canonical name to assign to the cname_resource.
+  \return Canonical Name
+  */
+       const string& canonicalname(const string& s)
+  {
+    return canonicalname(s.c_str());
+  }
+
+  /*!
+  Sets the Canonical name
+
+  \param s Canonical name string to assign to the cname_resource.
+  \return Canonical name
+  */
+  const string& canonicalname(const char* s)
+  {
+    rr_cname = s;
+    return rr_cname;
+  }
+
+  /*!
+  Gets the Canonical name
+
+  \return Canonical name
+  */
+  const string& canonicalname() const
+  {
+    return rr_cname;
+  }
+
+  /*!
+  Clones an existing resource record object
+  */
+  virtual shared_resource_base_t clone() const
+  {
+    return shared_resource_base_t(new cname_resource(*this));
+  }
+
+  /// Friend to tie to the containers in the message class.
+  friend class message;
+
+protected:
+  /*!
+  Copy Constructor
+
+  \param o cname_resource to copy from
+  */
+  cname_resource(const cname_resource& o) : resource_base_t(o), rr_cname(o.rr_cname) { ; }
+
+  /*!
+  Copy Constructor
+
+  \param o resource_base_t to copy from
+  */
+  cname_resource(const resource_base_t& o) : resource_base_t(o), rr_cname() { ; }
+
+  /*!
+  Encodes the cname resource into a memory buffer
+
+  \param buffer Buffer to encode the request into
+  \param offset_map DNS label compression map for label/offset values
+  */
+  virtual void encode(dns_buffer_t& buffer, rfc1035_414_t& offset_map)
+  {
+    resource_base_t::encode(buffer, offset_map);
+
+    size_t lenOffset( buffer.position() - sizeof(uint16_t) );
+    size_t len = offset_map.write_label(rr_cname, buffer);
+
+    // lastly, update the length field
+    buffer.put( (uint16_t)len, lenOffset, false );
+  }
+
+  /*!
+  Decodes the cname resource into a memory buffer
+
+  \param buffer Buffer to decode the request into
+  \param offset_map DNS label compression map for label/offset values
+  */
+  virtual void decode(dns_buffer_t& buffer, rfc1035_414_t& offset_map)
+  {
+    offset_map.read_label(rr_cname, buffer);
+  }
+};
+
+/*!
+Definition of a SOA resource
+*/
+class soa_resource : public resource_base_t
+{
+protected:
+  /// Master Name
+  string         rr_mname;
+  /// Responsible Name
+  string         rr_rname;
+  /// Serial Number for SOA record
+  uint32_t  rr_serial;
+  /// Refresh Time
+  uint32_t  rr_refresh;
+  /// Retry Time
+  uint32_t  rr_retry;
+  /// Exipiration Time
+  uint32_t  rr_expire;
+  /// Minimum TTL
+  uint32_t  rr_minttl;
+
+public:
+  /// Default contructor
+  soa_resource()
+  : resource_base_t(type_soa),
+    rr_mname(),
+    rr_rname(),
+    rr_serial(0),
+    rr_refresh(0),
+    rr_retry(0),
+    rr_expire(0),
+    rr_minttl(0)
+  {
+      ;
+  }
+
+  /*!
+  Constructs a soa_resource
+
+  \param s Host name for the SOA record
+  */
+  soa_resource(const string& s)
+  : resource_base_t(s, type_soa),
+    rr_mname(),
+    rr_rname(),
+    rr_serial(0),
+    rr_refresh(0),
+    rr_retry(0),
+    rr_expire(0),
+    rr_minttl(0)
+  {
+      ;
+  }
+
+  /// Virtual Destructor
+  virtual ~soa_resource()
+  {
+  }
+
+  /*!
+  Sets the Master Name
+
+  \param s Master Name to assign to the soa_resource.
+  \return Master Name
+  */
+       const string& master_name(const string& s)
+  {
+    return master_name(s.c_str());
+  }
+
+  /*!
+  Sets the Master Name
+
+  \param s Master Name string to assign to the soa_resource.
+  \return Master Name
+  */
+  const string& master_name(const char* s)
+  {
+    rr_mname = s;
+    return rr_mname;
+  }
+
+  /*!
+  Gets the Master Name
+
+  \return Master Name
+  */
+  const string& master_name() const
+  {
+    return rr_mname;
+  }
+
+  /*!
+  Sets the Responsible Name
+
+  \param s Responsible Name to assign to the soa_resource.
+  \return Responsible Name
+  */
+       const string& responsible_name(const string& s)
+  {
+    return responsible_name(s.c_str());
+  }
+
+  /*!
+  Sets the Responsible Name
+
+  \param s Responsible Name to assign to the soa_resource.
+  \return Responsible Name
+  */
+  const string& responsible_name(const char* s)
+  {
+    rr_rname = s;
+    return rr_rname;
+  }
+
+  /*!
+  Gets the Responsible Name
+
+  \return Responsible Name
+  */
+  const string& responsible_name() const
+  {
+    return rr_rname;
+  }
+
+  /*!
+  Sets the Serial number
+
+  \param d Serial number to assign to the soa_resouce.
+  \return Serial number
+  */
+  uint32_t serial_number(const uint32_t d)
+  {
+    rr_serial = d;
+    return rr_serial;
+  }
+
+  /*!
+  Gets the Serial number
+
+  \return Serial number
+  */
+  uint32_t serial_number() const
+  {
+    return rr_serial;
+  }
+
+  /*!
+  Sets the refresh time
+
+  \param d Refresh time to assign to the soa_resouce.
+  \return Refresh time
+  */
+  uint32_t refresh(const uint32_t d)
+  {
+    rr_refresh = d;
+    return rr_refresh;
+  }
+
+  /*!
+  Gets the refresh time
+
+  \return Refresh time
+  */
+  uint32_t refresh() const
+  {
+    return rr_refresh;
+  }
+
+  /*!
+  Sets the Retry time
+
+  \param d Retry time to assign to the soa_resouce.
+  \return Retry time
+  */
+  uint32_t retry(const uint32_t d)
+  {
+    rr_retry = d;
+    return rr_retry;
+  }
+
+  /*!
+  Gets the Retry time
+
+  \return Retry time
+  */
+  uint32_t retry() const
+  {
+    return rr_retry;
+  }
+
+  /*!
+  Sets the Exipiration time
+
+  \param d Exipiration time to assign to the soa_resouce.
+  \return Exipiration time
+  */
+  uint32_t expire(const uint32_t d)
+  {
+    rr_expire = d;
+    return rr_expire;
+  }
+
+  /*!
+  Gets the Exipiration time
+
+  \return Exipiration time
+  */
+  uint32_t expire() const
+  {
+    return rr_expire;
+  }
+
+  /*!
+  Sets the Minimum TTL
+
+  \param d Minimum TTL to assign to the soa_resouce.
+  \return Minimum TTL
+  */
+  uint32_t minttl(const uint32_t d)
+  {
+    rr_minttl = d;
+    return rr_minttl;
+  }
+
+  /*!
+  Gets the Minimum TTL
+
+  \return Minimum TTL
+  */
+  uint32_t minttl() const
+  {
+    return rr_minttl;
+  }
+
+  /*!
+  Clones an existing resource record object
+  */
+  virtual shared_resource_base_t clone() const
+  {
+    return shared_resource_base_t(new soa_resource(*this));
+  }
+
+  /// Friend to tie to the containers in the message class.
+  friend class message;
+
+protected:
+  /*!
+  Copy Constructor
+
+  \param o soa_resource to copy from
+  */
+  soa_resource(const soa_resource& o)
+  : resource_base_t(o),
+    rr_mname(o.rr_mname),
+    rr_rname(o.rr_rname),
+    rr_serial(o.rr_serial),
+    rr_refresh(o.rr_refresh),
+    rr_retry(o.rr_retry),
+    rr_expire(o.rr_expire),
+    rr_minttl(o.rr_minttl)
+  {
+  }
+
+  /*!
+  Copy Constructor
+
+  \param o resource_base_t to copy from
+  */
+  soa_resource(const resource_base_t& o)
+  : resource_base_t(o),
+    rr_mname(),
+    rr_rname(),
+    rr_serial(0),
+    rr_refresh(0),
+    rr_retry(0),
+    rr_expire(0),
+    rr_minttl(0)
+  {
+      ;
+  }
+
+  /*!
+  Encodes the soa resource into a memory buffer
+
+  \param buffer Buffer to encode the request into
+  \param offset_map DNS label compression map for label/offset values
+  */
+  virtual void encode(dns_buffer_t& buffer, rfc1035_414_t& offset_map)
+  {
+    resource_base_t::encode(buffer, offset_map);
+
+    size_t lenOffset( buffer.position() - sizeof(uint16_t) );
+    size_t len(0);
+
+    len += offset_map.write_label(rr_mname, buffer);
+    len += offset_map.write_label(rr_rname, buffer);
+    len += buffer.put( rr_serial );
+    len += buffer.put( rr_refresh );
+    len += buffer.put( rr_retry );
+    len += buffer.put( rr_expire );
+    len += buffer.put( rr_minttl );
+
+    // lastly, update the length field
+    buffer.put( (uint16_t)len, lenOffset, false );
+  }
+
+  /*!
+  Decodes the soa_resource into a memory buffer
+
+  \param buffer Buffer to decode the request into
+  \param offset_map DNS label compression map for label/offset values
+  */
+  virtual void decode(dns_buffer_t& buffer, rfc1035_414_t& offset_map)
+  {
+    offset_map.read_label(rr_mname, buffer);
+    offset_map.read_label(rr_rname, buffer);
+
+    buffer.get( rr_serial );
+    buffer.get( rr_refresh );
+    buffer.get( rr_retry );
+    buffer.get( rr_expire );
+    buffer.get( rr_minttl );
+  }
+
+};
+
+/*!
+Definition of a PTR resource
+*/
+class ptr_resource : public resource_base_t
+{
+protected:
+  /// Pointer name
+  string rr_ptrdname;
+
+public:
+  /// Default contructor
+  ptr_resource() : resource_base_t(type_ptr), rr_ptrdname() {;}
+
+  /// Constructs a ptr_resource
+  /*
+  \param s Host name for the PTR record
+  */
+  ptr_resource(const string& s) : resource_base_t(s, type_ptr), rr_ptrdname(s) {;}
+
+  /// Virtual Destructor
+  virtual ~ptr_resource()
+  {
+  }
+
+       /// Pointer set function
+  /*
+  \param t Pointer to assign to the ptr_resource.
+  \return Pointer
+  */
+       const string& pointer(const string& s)
+  {
+    return pointer(s.c_str());
+  }
+
+  /// Pointer get/set function
+  /*
+  \param t Pointer string to assign to the ptr_resource. If left blank, will return the
+  current pointer only.
+  \return Pointer
+  */
+  const string& pointer(const char* s=0)
+  {
+    if( s ) rr_ptrdname = s;
+    return rr_ptrdname;
+  }
+
+  /*!
+  Clones an existing resource record object
+  */
+  virtual shared_resource_base_t clone() const
+  {
+    return shared_resource_base_t(new ptr_resource(*this));
+  }
+
+  /// Friend to tie to the containers in the message class.
+  friend class message;
+
+protected:
+  /// Copy Constructor
+  /*
+  \param o ptr_resource to copy from
+  */
+  ptr_resource(const ptr_resource& o) : resource_base_t(o), rr_ptrdname(o.rr_ptrdname) { ; }
+
+  /// Copy Constructor
+  /*
+  \param o resource_base_t to copy from
+  */
+  ptr_resource(const resource_base_t& o) : resource_base_t(o), rr_ptrdname() { ; }
+
+  /// Encodes the ptr resource into a memory buffer
+  /*
+  \param buffer Buffer to encode the request into
+  \param offset_map DNS label compression map for label/offset values
+  */
+  virtual void encode(dns_buffer_t& buffer, rfc1035_414_t& offset_map)
+  {
+    resource_base_t::encode(buffer, offset_map);
+
+    size_t lenOffset( buffer.position() - sizeof(uint16_t) );
+    size_t len = offset_map.write_label(rr_ptrdname, buffer);
+
+    buffer.put( (uint16_t)len, lenOffset, false );
+  }
+
+  /// Decodes the ptr resource into a memory buffer
+  /*
+  \param buffer Buffer to decode the request into
+  */
+  virtual void decode(dns_buffer_t& buffer, rfc1035_414_t& offset_map)
+  {
+    offset_map.read_label(rr_ptrdname, buffer);
+  }
+};
+
+/// Definition of a HINFO resource
+/**
+*/
+class hinfo_resource : public resource_base_t
+{
+protected:
+  /// CPU description
+  string       rr_cpu;
+  /// OS description
+  string       rr_os;
+
+public:
+  /// Default contructor
+  hinfo_resource() : resource_base_t(type_hinfo), rr_cpu(), rr_os() {;}
+
+  /// Constructs a hinfo_resource
+  /*
+  \param s Host name for the PTR record
+  */
+  hinfo_resource(const string& s) : resource_base_t(s, type_hinfo), rr_cpu(), rr_os() {;}
+
+  /// Virtual Destructor
+  virtual ~hinfo_resource()
+  {
+  }
+
+       /// CPU description set function
+  /*
+  \param t CPU description to assign to the hinfo_resource.
+  \return CPU description
+  */
+       const string& cpu(const string& s)
+  {
+    return cpu(s.c_str());
+  }
+
+  /// CPU description get/set function
+  /*
+  \param t CPU description string to assign to the hinfo_resource. If left blank, will return the
+  current CPU description only.
+  \return CPU description
+  */
+  const string& cpu(const char* s=0)
+  {
+    if( s ) rr_cpu = s;
+    return rr_cpu;
+  }
+
+       /// OS description set function
+  /*
+  \param t OS description to assign to the hinfo_resource.
+  \return OS description
+  */
+       const string& os(const string& s)
+  {
+    return os(s.c_str());
+  }
+
+  /// OS description get/set function
+  /*
+  \param t OS description string to assign to the hinfo_resource. If left blank, will return the
+  current OS description only.
+  \return OS description
+  */
+  const string& os(const char* s=0)
+  {
+    if( s ) rr_os = s;
+    return rr_os;
+  }
+
+  /*!
+  Clones an existing resource record object
+  */
+  virtual shared_resource_base_t clone() const
+  {
+    return shared_resource_base_t(new hinfo_resource(*this));
+  }
+
+  /// Friend to tie to the containers in the message class.
+  friend class message;
+
+protected:
+  /// Copy Constructor
+  /*
+  \param o hinfo_resource to copy from
+  */
+  hinfo_resource(const hinfo_resource& o) : resource_base_t(o), rr_cpu(o.rr_cpu), rr_os(o.rr_os) { ; }
+
+  /// Copy Constructor
+  /*
+  \param o resource_base_t to copy from
+  */
+  hinfo_resource(const resource_base_t& o) : resource_base_t(o), rr_cpu(), rr_os() { ; }
+
+  /// Encodes the hinfo resource into a memory buffer
+  /*
+  \param buffer Buffer to encode the request into
+  \param offset_map DNS label compression map for label/offset values
+  */
+  virtual void encode(dns_buffer_t& buffer, rfc1035_414_t& offset_map)
+  {
+    resource_base_t::encode(buffer, offset_map);
+
+    size_t lenOffset( buffer.position() - sizeof(uint16_t) );
+    size_t len(0);
+
+    len += buffer.put( (uint8_t)rr_cpu.length() );
+    len += buffer.put( rr_cpu, rr_cpu.length() );
+    len += buffer.put( (uint8_t)rr_os.length() );
+    len += buffer.put( rr_os, rr_os.length() );
+
+    // lastly, update the length field
+    buffer.put( (uint16_t)len, lenOffset, false );
+  }
+
+  /// Decodes the hinfo resource into a memory buffer
+  /*
+  \param buffer Buffer to decode the request into
+  */
+  virtual void decode(dns_buffer_t& buffer, rfc1035_414_t& /*offset_map*/)
+  {
+    uint16_t len(0);
+
+    buffer.get(len);
+    buffer.get(rr_cpu, len);
+
+    buffer.get(len);
+    buffer.get(rr_os, len);
+  }
+};
+
+/// Definition of a MX resource
+/*
+*/
+class mx_resource : public resource_base_t
+{
+protected:
+  /// Preference value
+  uint16_t  rr_preference;
+  /// Mail Exchange(server)
+  string    rr_exchange;
+
+public:
+  /// Default contructor
+  mx_resource() : resource_base_t(type_mx), rr_preference(0), rr_exchange() {}
+
+  /// Constructs a mx_resource
+  /*
+  \param s Host name for the MX record
+  */
+  mx_resource(const string& s) : resource_base_t(s, type_mx), rr_preference(0), rr_exchange() {}
+
+  /// Virtual Destructor
+  virtual ~mx_resource()
+  {
+  }
+
+       /// Mail exchange(server) set function
+  /*
+  \param t Mail exchange(server) to assign to the mx_resource.
+  \return Mail exchange(server)
+  */
+       const string& exchange(const string& s)
+  {
+    return exchange(s.c_str());
+
+  }
+
+  /// Mail Exchange(server) get/set function
+  /*
+  \param t Mail exchange(server) string to assign to the mx_resource. If left blank, will return the
+  current mail exchange(server) only.
+  \return Mail exchange(server)
+  */
+  const string& exchange(const char* s=0)
+  {
+    if( s ) rr_exchange = s;
+    return rr_exchange;
+  }
+
+  /// Preference value get/set function
+  /*
+  \param t Preference value to assign to the mx_resource. If left blank, will return the
+  current preference value only.
+  \return Preference value
+  */
+  uint16_t preference(const uint16_t d = 0xffff)
+  {
+    if( d != 0xffff ) rr_preference = d;
+    return rr_preference;
+  }
+
+  /*!
+  Clones an existing resource record object
+  */
+  virtual shared_resource_base_t clone() const
+  {
+    return shared_resource_base_t(new mx_resource(*this));
+  }
+
+  /// Friend to tie to the containers in the message class.
+  friend class message;
+
+protected:
+  /// Copy Constructor
+  /*
+  \param o mx_resource to copy from
+  */
+  mx_resource(const mx_resource& o)
+  : resource_base_t(o),
+    rr_preference(o.rr_preference),
+    rr_exchange(o.rr_exchange)
+  {
+      ;
+  }
+
+  /// Copy Constructor
+  /*
+  \param o resource_base_t to copy from
+  */
+  mx_resource(const resource_base_t& o)
+  : resource_base_t(o),
+    rr_preference(0),
+    rr_exchange()
+  { }
+
+
+  /// Encodes the mx resource into a memory buffer
+  /*
+  \param buffer Buffer to encode the request into
+  \param offset_map DNS label compression map for label/offset values
+  */
+  virtual void encode(dns_buffer_t& buffer, rfc1035_414_t& offset_map)
+  {
+    resource_base_t::encode(buffer, offset_map);
+
+    size_t lenOffset( buffer.position() - sizeof(uint16_t) );
+    size_t len(0);
+
+    len += buffer.put( rr_preference );
+    len += offset_map.write_label(rr_exchange, buffer);
+
+    // lastly, update the length field
+    buffer.put( (uint16_t)len, lenOffset, false );
+  }
+
+  /// Decodes the mx resource into a memory buffer
+  /*
+  \param buffer Buffer to decode the request into
+  */
+  virtual void decode(dns_buffer_t& buffer, rfc1035_414_t& offset_map)
+  {
+    buffer.get( rr_preference );
+    offset_map.read_label(rr_exchange, buffer);
+  }
+
+};
+
+/// Definition of a TXT resource
+/**
+*/
+class txt_resource : public resource_base_t
+{
+protected:
+  /// Text string
+  string       rr_text;
+
+public:
+  /// Default contructor
+  txt_resource() : resource_base_t(type_txt), rr_text() {;}
+
+  /// Constructs a txt_resource
+  /*
+  \param s Host name for the TXT record
+  */
+  txt_resource(const string& s) : resource_base_t(s, type_txt), rr_text(s) {;}
+
+  /// Virtual Destructor
+  virtual ~txt_resource()
+  {
+  }
+
+       /// Text string set function
+  /*
+  \param t Text string to assign to the txt_resource.
+  \return Text string
+  */
+       const string& text(const string& s)
+  {
+    return text(s.c_str());
+  }
+
+  /// Text string get/set function
+  /*
+  \param t Text string to assign to the txt_resource. If left blank, will return the
+  current text string only.
+  \return Text string
+  */
+  const string& text(const char* s=0)
+  {
+    if( s ) rr_text = s;
+    return rr_text;
+  }
+
+  /*!
+  Clones an existing resource record object
+  */
+  virtual shared_resource_base_t clone() const
+  {
+    return shared_resource_base_t(new txt_resource(*this));
+  }
+
+  /// Friend to tie to the containers in the message class.
+  friend class message;
+
+protected:
+  /// Copy Constructor
+  /*
+  \param o txt_resource to copy from
+  */
+  txt_resource(const txt_resource& o) : resource_base_t(o), rr_text(o.rr_text) { ; }
+
+  /// Copy Constructor
+  /*
+  \param o resource_base_t to copy from
+  */
+  txt_resource(const resource_base_t& o) : resource_base_t(o), rr_text() { ; }
+
+  /// Encodes the txt resource into a memory buffer
+  /*
+  \param buffer Buffer to encode the request into
+  \param offset_map DNS label compression map for label/offset values
+  */
+  virtual void encode(dns_buffer_t& buffer, rfc1035_414_t& offset_map)
+  {
+    resource_base_t::encode(buffer, offset_map);
+
+    size_t lenOffset( buffer.position() - sizeof(uint16_t) );
+    size_t len(0);
+
+    len += buffer.put( (uint8_t)rr_text.length() );
+    len += buffer.put( rr_text, rr_text.length() );
+
+    // lastly, update the length field
+    buffer.put( (uint16_t)len, lenOffset, false );
+  }
+
+  /// Decodes the txt resource into a memory buffer
+  /*
+  \param buffer Buffer to decode the request into
+  */
+  virtual void decode(dns_buffer_t& buffer, rfc1035_414_t& /*offset_map*/)
+  {
+    uint8_t  len;
+    buffer.get(len);
+    buffer.get(rr_text, len);
+  }
+
+};
+
+/// Definition for an A6 resource record
+/*
+*/
+class a6_resource : public resource_base_t
+{
+protected:
+  /// IP 6 address
+  ip::address_v6 rr_address;
+
+public:
+  /// Default contructor
+  a6_resource() : resource_base_t(type_a6), rr_address() {;}
+
+  /// Constructs a a6_resource
+  /*
+  \param s Host name for the A record
+  */
+  a6_resource(const string& s) : resource_base_t(s, type_a6), rr_address() {;}
+
+  /// Virtual Destructor
+  virtual ~a6_resource()
+  {
+  }
+
+  /// Address set function
+  /*
+  \param t Address to assign to the a6_resource.
+  \return Address
+  */
+       const ip::address_v6& address(const ip::address_v6& addr)
+  {
+    rr_address = addr;
+    return rr_address;
+  }
+
+  /// Address get/set function
+  /*
+  \param t Dotted decimal address string to assign to the a6_resource. If left blank, will return the
+  current address only.
+  \return Address
+  */
+  const ip::address_v6& address(const char* s=0)
+  {
+    if( s != 0 )  return address(ip::address_v6::from_string(s));
+    return rr_address;
+  }
+
+  /*!
+  Clones an existing resource record object
+  */
+  virtual shared_resource_base_t clone() const
+  {
+    return shared_resource_base_t(new a6_resource(*this));
+  }
+
+  /// Friend to tie to the containers in the message class.
+  friend class message;
+
+protected:
+  /// Copy Constructor
+  /*
+  \param o a6_resource to copy from
+  */
+  a6_resource(const a6_resource& o) : resource_base_t(o), rr_address(o.rr_address) { ; }
+
+  /// Copy Constructor
+  /*
+  \param o resource_base_t to copy from
+  */
+  a6_resource(const resource_base_t& o) : resource_base_t(o), rr_address() { ; }
+
+  /// Encodes the a resource into a memory buffer
+  /*
+  \param buffer Buffer to encode the request into
+  \param offset_map DNS label compression map for label/offset values
+  */
+  virtual void encode(dns_buffer_t& buffer, rfc1035_414_t& offset_map)
+  {
+    resource_base_t::encode(buffer, offset_map);
+
+    // the length offset for the resource record
+    size_t lenOffset( buffer.position() - sizeof(uint16_t) );
+
+    size_t len(0);
+
+    len = buffer.put( rr_address );
+
+    // lastly, update the length field
+    buffer.put( (uint16_t)len, lenOffset, false );
+  }
+
+  /// Decodes the a resource into a memory buffer
+  /*
+  \param buffer Buffer to decode the request into
+  */
+  virtual void decode(dns_buffer_t& buffer, rfc1035_414_t& /*offset_map*/)
+  {
+    buffer.get(rr_address);
+  }
+};
+
+/// Definition of a SRV resource
+/*
+*/
+class srv_resource : public resource_base_t
+{
+protected:
+  uint16_t  rr_priority;  //!< Priority of the target host
+  uint16_t  rr_weight;    //!< Weight of the record, used as a selection method
+  uint16_t  rr_port;      //!< Port for the target host's service
+  string    rr_target;    //!< Target name of the host
+
+public:
+  /// Default contructor
+  srv_resource()
+  : resource_base_t(type_srv),
+    rr_priority(0),
+    rr_weight(0),
+    rr_port(0),
+    rr_target()
+  {
+      ;
+  }
+
+  /// Constructs a srv_resource
+  /*
+  \param s Host name for the TXT record
+  */
+  srv_resource(const string& s)
+  : resource_base_t(s, type_srv),
+    rr_priority(0),
+    rr_weight(0),
+    rr_port(0),
+    rr_target(s)
+    {
+        ;
+    }
+
+  /// Virtual Destructor
+  virtual ~srv_resource()
+  {
+  }
+
+  /// Priority value get/set function
+  /*
+  \param t Priority value to assign to the srv_resource. If left blank, will return the current priority value only.
+  \return Priority value
+  */
+  uint16_t priority(const uint16_t d = 0xffff)
+  {
+    if( d != 0xffff ) rr_priority = d;
+    return rr_priority;
+  }
+
+  /// Weight value get/set function
+  /*
+  \param t Weight value to assign to the srv_resource. If left blank, will return the current weight value only.
+  \return Weight value
+  */
+  uint16_t weight(const uint16_t d = 0xffff)
+  {
+    if( d != 0xffff ) rr_weight = d;
+    return rr_weight;
+  }
+
+  /// Port value get/set function
+  /*
+  \param t Port value to assign to the srv_resource. If left blank, will return the current port value only.
+  \return Port value
+  */
+  uint16_t port(const uint16_t d = 0xffff)
+  {
+    if( d != 0xffff ) rr_port = d;
+    return rr_port;
+  }
+
+       /// Target host set function
+  /*
+  \param t Target host string to assign to the srv_resource.
+  \return Target host string
+  */
+       const string& targethost(const string& s)
+  {
+    return targethost(s.c_str());
+
+  }
+
+  /// Target host  get/set function
+  /*
+  \param t Target host  name to assign to the srv_resource. If left blank, will return the current target host string only.
+  \return Target host string
+  */
+  const string& targethost(const char* s=0)
+  {
+    if( s ) rr_target = s;
+    return rr_target;
+  }
+
+  /*!
+  Clones an existing resource record object
+  */
+  virtual shared_resource_base_t clone() const
+  {
+    return shared_resource_base_t(new srv_resource(*this));
+  }
+
+  /// Friend to tie to the containers in the message class.
+  friend class message;
+
+protected:
+  /// Copy Constructor
+  /*
+  \param o srv_resource to copy from
+  */
+  srv_resource(const srv_resource& o)
+  : resource_base_t(o),
+    rr_priority(o.rr_priority),
+    rr_weight(o.rr_weight),
+    rr_port(o.rr_port),
+    rr_target(o.rr_target)
+  {
+      ;
+  }
+
+  /// Copy Constructor
+  /*
+  \param o resource_base_t to copy from
+  */
+  srv_resource(const resource_base_t& o)
+  : resource_base_t(o),
+    rr_priority(0),
+    rr_weight(0),
+    rr_port(0),
+    rr_target()
+  {
+      ;
+  }
+
+
+  /// Encodes the srv resource into a memory buffer
+  /*
+  \param buffer Buffer to encode the request into
+  \param offset_map DNS label compression map for label/offset values
+  */
+  virtual void encode(dns_buffer_t& buffer, rfc1035_414_t& offset_map)
+  {
+    resource_base_t::encode(buffer, offset_map);
+
+    size_t lenOffset( buffer.position() - sizeof(uint16_t) );
+    size_t len(0);
+
+    len += buffer.put(rr_priority);
+    len += buffer.put(rr_weight);
+    len += buffer.put(rr_port);
+    len += offset_map.write_label(rr_target, buffer);
+
+    // lastly, update the length field
+    buffer.put( (uint16_t)len, lenOffset, false );
+  }
+
+  /// Decodes the srv resource into a memory buffer
+  /*
+  \param buffer Buffer to decode the request into
+  */
+  virtual void decode(dns_buffer_t& buffer, rfc1035_414_t& offset_map)
+  {
+    buffer.get(rr_priority);
+    buffer.get(rr_weight);
+    buffer.get(rr_port);
+    offset_map.read_label(rr_target, buffer);
+  }
+
+};
+
+/// DNS Request/Response Message
+/**
+*/
+class message
+{
+private:
+  /// Bit fields for the header
+  typedef      struct  bit_fields_header
+       {
+    /// Defines the action of the message, query/response
+               uint16_t        Action:1,
+    /// Operation code of the message
+                                   OpCode:4,
+    /// Defines if the message is from an authority
+                                           Authority:1,
+    /// Defines if the message was truncated due to size limitation of the transmission channel
+                                           Truncated:1,
+    /// Defines if name server being queried should recursively find an answer.
+                                   RD:1,
+    /// Defines if the names server supports recursive queries
+                                           RA:1,
+    /// Reserved bits
+                                           Z:3,
+    /// Response code for the query
+                                           RCODE:4;
+       } bit_fields_header;
+
+  /// Header bytes of the message
+       typedef struct opaque_header
+       {
+    /// Message id
+               uint16_t        Id;
+    /// Bitfields as defined in the bit_fields_header structure
+               uint16_t        bit_fields;
+    /// Question count
+               uint16_t        QdCount;
+    /// Resource record answer count
+               uint16_t        AnCount;
+    /// Name server count
+               uint16_t        NsCount;
+    /// Additional resource records
+               uint16_t        ArCount;
+       } opaque_header;
+
+public:
+  /// Used by the action field of the header
+       typedef enum
+       {
+    /// No action to take.
+    no_action = -1,
+    /// Query the name server
+               query = 0,
+    /// Response from the name server
+               response
+       } action_t;
+
+  /// Specifies the type of request operation.
+       typedef enum
+       {
+    /// No operation to take
+    no_opcode = -1,
+    /// Standard query
+               squery = 0,
+    /// Inverse query
+               iquery,
+    /// Server status query
+               status
+       } opcode_t;
+
+  /// Response codes from a request operation
+       typedef enum
+       {
+    /// No error
+               noerror = 0,
+    /// Message is malformed
+               format_error,
+    /// Server had an internal error
+               server_error,
+    /// The domain name does not exist on the name server being queried
+               name_error,
+    /// Name server does not support the query
+               not_implemented,
+    /// Name server refused the request
+               refused,
+    /// No result
+    no_result
+       } result_t;
+
+  /// A list of questions
+  typedef std::vector<question>               questions_t;
+
+private:
+  /// Header bytes of the message
+  uint8_t                header[sizeof(opaque_header)];
+
+  /// Question list
+       questions_t question_section;
+  /// Answer list
+       rr_list_t   answer_section;
+  /// Authoritative records list
+       rr_list_t   authority_section;
+  /// Additional records list
+       rr_list_t   additional_section;
+
+public:
+  /// Default constructor
+  message()
+  : question_section(),
+    answer_section(),
+    authority_section(),
+    additional_section()
+  {
+    memset(&header, 0x00, sizeof(header));
+  }
+
+  /*!
+  Constructs a query message with a default question
+
+  \param q question to ask
+  */
+  message( const dns::question& q)
+  : question_section(),
+    answer_section(),
+    authority_section(),
+    additional_section()
+  {
+    memset(&header, 0x00, sizeof(header));
+    question_section.push_back( q );
+
+    recursive(true);
+    action(dns::message::query);
+    opcode(dns::message::squery);
+  }
+
+  /*!
+  Constructs a query message with a default question
+
+  \param d Domain to query
+  \param t Resource type to query
+  */
+  message(const string & d, const type_t t)
+  : question_section(),
+    answer_section(),
+    authority_section(),
+    additional_section()
+  {
+    memset(&header, 0x00, sizeof(header));
+    question_section.push_back( dns::question(d, t) );
+
+    recursive(true);
+    action(dns::message::query);
+    opcode(dns::message::squery);
+  }
+
+  /*!
+  Copy constructor
+
+  \param p message to copy from
+  */
+  message(const message& p)
+  : question_section(),
+    answer_section(),
+    authority_section(),
+    additional_section()
+  {
+    operator=(p);
+  }
+
+  /*!
+  Assignment operator
+
+  \param p message to assign from
+  */
+  message& operator=(const message& p)
+  {
+         memcpy(&header, &p.header, sizeof(header));
+
+    rr_list_t::const_iterator   rIter;
+    questions_t::const_iterator qIter;
+
+    question_section.clear();
+    for( qIter = p.question_section.begin(); qIter != p.question_section.end(); ++qIter)
+      question_section.push_back( (*qIter) );
+
+    answer_section.clear();
+    for( rIter = p.answer_section.begin(); rIter != p.answer_section.end(); ++rIter)
+      answer_section.push_back( (*rIter) );
+
+    authority_section.clear();
+    for( rIter = p.authority_section.begin(); rIter != p.authority_section.end(); ++rIter)
+      authority_section.push_back( (*rIter) );
+
+    additional_section.clear();
+    for( rIter = p.additional_section.begin(); rIter != p.additional_section.end(); ++rIter)
+      additional_section.push_back( (*rIter) );
+
+         return *this;
+  }
+
+  /*!
+  Set the message id
+  \param d Message id to assign to the message
+  \return id
+  */
+  uint16_t id(const uint16_t d)
+  {
+    ((opaque_header*)header)->Id = d;
+    return  ((opaque_header*)header)->Id;
+  }
+
+  /*!
+  Get the message id
+
+  \return id
+  */
+  uint16_t id() const
+  {
+    return  ((opaque_header*)header)->Id;
+  }
+
+  /*!
+  Sets the Query action
+
+  \param e Query action to assign to the message.
+  \return query action
+  */
+  action_t action(const action_t e)
+  {
+    (e == query) ?
+      ((opaque_header*)header)->bit_fields &= static_cast<uint16_t>(~0x8000) :
+      ((opaque_header*)header)->bit_fields |= static_cast<uint16_t>(0x8000);
+
+    return (action_t)(((opaque_header*)header)->bit_fields & 0x8000);
+  }
+
+  /*!
+  Gets the Query action
+
+  \return query action
+  */
+  action_t action() const
+  {
+    return (action_t)(((opaque_header*)header)->bit_fields & 0x8000);
+  }
+
+
+  /*!
+  Sets the Opcode
+
+  \param oc Opcode to assign to the message.
+  \return Opcode
+  */
+  opcode_t  opcode(const opcode_t oc)
+  {
+    switch( oc )
+    {
+    case squery:
+      ((opaque_header*)header)->bit_fields &= static_cast<uint16_t>(~0x3000);
+      return squery;
+    case iquery:
+      ((opaque_header*)header)->bit_fields |= 0x1000;
+      return iquery;
+    case status:
+      ((opaque_header*)header)->bit_fields |= 0x2000;
+      return status;
+    case no_opcode:
+      break;
+    }
+
+    if( ((opaque_header*)header)->bit_fields & 0x1000 )
+      return iquery;
+    if( ((opaque_header*)header)->bit_fields & 0x2000 )
+      return status;
+
+    return squery;
+  }
+
+  /*!
+  Gets the Opcode
+
+  \return Opcode
+  */
+  opcode_t  opcode() const
+  {
+    if( ((opaque_header*)header)->bit_fields & 0x1000 )
+      return iquery;
+    if( ((opaque_header*)header)->bit_fields & 0x2000 )
+      return status;
+
+    return squery;
+  }
+
+  /*!
+  Sets the 'authority' field
+
+  Setting the 'authority' field is a function used by servers that are answering a request.
+
+  \param _authority True if the server answering is the authority
+  */
+       void  authority(const bool _authority)
+  {
+    (_authority) ? ((opaque_header*)header)->bit_fields |= static_cast<uint16_t>(0x400) :
+                   ((opaque_header*)header)->bit_fields &= static_cast<uint16_t>(~0x400);
+  }
+
+  /*!
+  Gets the 'authority' field
+
+  \return True if the server answering is the authority
+  */
+  bool is_authority() const
+  {
+    return( ((opaque_header*)header)->bit_fields & 0x400 );
+  }
+
+  /*!
+  Sets the 'truncated' field.
+
+  Setting the 'truncated' field  is a function used by servers to notify the
+  client that message has been truncated, due to the large volume of answers.
+
+  \param  _truncated True if the server is truncating
+  */
+  void  truncated(const bool _truncated)
+  {
+    (_truncated) ? ((opaque_header*)header)->bit_fields |= static_cast<uint16_t>(0x200) :
+                   ((opaque_header*)header)->bit_fields &= static_cast<uint16_t>(~0x200);
+  }
+
+  /*!
+  Gets the 'truncated' field
+
+  \return True if the server is truncating the message
+  */
+  bool is_truncated() const  { return( ((opaque_header*)header)->bit_fields & 0x200 ); }
+
+  /*!
+  Sets the 'recursive' field.
+
+  Setting the 'recursive' field is a function used by clients to notify the
+  server that message if the DNS question is not answerable by the server, the
+  server can ask other DNS servers for a response.
+
+  \param  recursive True if the server should recursively seek an answer.
+  */
+  void  recursive(const bool _recursive)
+  {
+    (_recursive) ? ((opaque_header*)header)->bit_fields |= static_cast<uint16_t>(0x100) :
+                   ((opaque_header*)header)->bit_fields &= static_cast<uint16_t>(~0x100);
+  }
+
+  /*!
+  Gets the 'recursive' field.
+
+  \return True if the server can recursively seek an answer.
+  */
+  bool is_recursive() const  { return( ((opaque_header*)header)->bit_fields & 0x100 ); }
+
+  /*!
+  Sets the 'recursion availability' field.
+
+  Setting the 'recursion availability' field is a function used by servers to notify the
+  client that recursion is supported. Some servers are only authority servers and do not
+  act as proxies when the domain does not reside with them.
+
+  \param  _recursion_avail True if the server can recursively seek an answer.
+  */
+  void  recursion_avail(const bool _recursion_avail)
+  {
+    (_recursion_avail) ? ((opaque_header*)header)->bit_fields |= static_cast<uint16_t>(0x80) :
+                         ((opaque_header*)header)->bit_fields &= static_cast<uint16_t>(~0x80);
+  }
+
+  /*!
+  Gets the 'recursion availability' field.
+
+  \return True if the server can recursively seek an answer.
+  */
+  bool is_recursion_avail() const
+  {
+    return( ((opaque_header*)header)->bit_fields & 0x80 );
+  }
+
+  /*!
+  Sets the result code for the message.
+
+  \param r Result code to assign to the message
+  \return Result code
+  */
+  result_t result(const result_t r)
+  {
+    switch( r )
+    {
+    case noerror:
+           ((opaque_header*)header)->bit_fields &= static_cast<uint16_t>(~0x07);
+           break;
+
+    default:
+           ((opaque_header*)header)->bit_fields |= static_cast<uint16_t>(r);
+           break;
+    }
+
+         if( ((opaque_header*)header)->bit_fields & 0x01 )
+                 return format_error;
+
+         if( ((opaque_header*)header)->bit_fields & 0x02 )
+                 return server_error;
+
+         if( ((opaque_header*)header)->bit_fields & 0x03 )
+                 return name_error;
+
+         if( ((opaque_header*)header)->bit_fields & 0x04 )
+                 return not_implemented;
+
+         if( ((opaque_header*)header)->bit_fields & 0x05 )
+                 return refused;
+
+         if( ((opaque_header*)header)->bit_fields & 0x06 )
+                 return no_result;
+
+         return noerror;
+  }
+
+  /*!
+  Gets the result code for the message.
+
+  \return Result code
+  */
+  result_t result() const
+  {
+         if( ((opaque_header*)header)->bit_fields & 0x01 )
+                 return format_error;
+
+         if( ((opaque_header*)header)->bit_fields & 0x02 )
+                 return server_error;
+
+         if( ((opaque_header*)header)->bit_fields & 0x03 )
+                 return name_error;
+
+         if( ((opaque_header*)header)->bit_fields & 0x04 )
+                 return not_implemented;
+
+         if( ((opaque_header*)header)->bit_fields & 0x05 )
+                 return refused;
+
+         if( ((opaque_header*)header)->bit_fields & 0x06 )
+                 return no_result;
+
+         return noerror;
+  }
+
+  /// Returns the questions container
+  questions_t*        questions()   { return &question_section; }
+  /// Returns the answers container
+  rr_list_t*          answers()     { return &answer_section; }
+  /// Returns the authorites container
+  rr_list_t*          authorites()  { return &authority_section; }
+  /// Returns the additionals container
+  rr_list_t*          additionals() { return &additional_section; }
+
+  /// Encodes the dns message into a memory buffer
+  /*
+  \param buffer Buffer to encode the message into
+  */
+  void  encode(dns_buffer_t& buffer)
+  {
+    // reset the buffer to the 0th position and reset the length
+    buffer.position(0);
+
+    rfc1035_414_t offset_map;
+
+    buffer.put( ((opaque_header*)header)->Id );
+    buffer.put( ((opaque_header*)header)->bit_fields );
+    buffer.put( (uint16_t)question_section.size() );
+    buffer.put( (uint16_t)answer_section.size() );
+    buffer.put( (uint16_t)authority_section.size() );
+    buffer.put( (uint16_t)additional_section.size() );
+
+    questions_t::iterator qiter;
+    for( qiter = question_section.begin(); qiter != question_section.end(); ++qiter )
+      ((question)*qiter).encode(buffer, offset_map);
+
+    rr_list_t::iterator riter;
+    for( riter = answer_section.begin(); riter != answer_section.end(); ++riter )
+      (*riter)->encode(buffer, offset_map);
+    for( riter = authority_section.begin(); riter != authority_section.end(); ++riter )
+      (*riter)->encode(buffer, offset_map);
+    for( riter = additional_section.begin(); riter != additional_section.end(); ++riter )
+      (*riter)->encode(buffer, offset_map);
+  }
+
+  /// Decodes the dns message into a memory buffer
+  /*
+  \param buffer Buffer to decode the message into
+  */
+  void  decode(dns_buffer_t& buffer)
+  {
+    // clean out the different sections
+    question_section.erase(question_section.begin(), question_section.end());
+    answer_section.erase(answer_section.begin(), answer_section.end());
+    authority_section.erase(authority_section.begin(), authority_section.end());
+    additional_section.erase(additional_section.begin(), additional_section.end());
+
+    // start at 0th
+    buffer.position(0);
+
+    opaque_header*      pHeader = (opaque_header*)header;
+
+    buffer.get( pHeader->Id );
+    buffer.get( pHeader->bit_fields );
+    buffer.get( pHeader->QdCount );
+    buffer.get( pHeader->AnCount );
+    buffer.get( pHeader->NsCount );
+    buffer.get( pHeader->ArCount );
+
+    rfc1035_414_t offset_map;
+
+    // read the sections
+    for( uint16_t i = 0; i < pHeader->QdCount; ++ i )
+      question_section.push_back( question(buffer, offset_map) );
+
+    for( uint16_t i = 0; i < pHeader->AnCount; ++ i )
+      answer_section.push_back( unpack_record(buffer,offset_map) );
+
+    for( uint16_t i = 0; i < pHeader->NsCount; ++ i )
+      authority_section.push_back( unpack_record(buffer,offset_map) );
+
+    for( uint16_t i = 0; i < pHeader->ArCount; ++ i )
+      additional_section.push_back( unpack_record(buffer,offset_map) );
+  }
+
+private:
+  shared_resource_base_t unpack_record(dns_buffer_t& buffer, rfc1035_414_t& offset_map)
+  {
+    shared_resource_base_t  ptr;
+
+    /*
+    catch 22, can't decode a "type" unless we know the "type"
+    So, we treat this as a pre-amble to the data and then decode the payload later
+    */
+    resource_base_t preamble;
+    preamble.decode(buffer, offset_map);
+
+               switch( preamble.rtype()  )
+    {
+    case type_a:
+      {
+        dns::a_resource*  aPtr = new dns::a_resource(preamble);
+        aPtr->decode(buffer, offset_map);
+        ptr = shared_resource_base_t(aPtr);
+      }
+      break;
+    case type_ns:
+      {
+        dns::ns_resource*  nsPtr = new dns::ns_resource(preamble);
+        nsPtr->decode(buffer, offset_map);
+        ptr = shared_resource_base_t(nsPtr);
+      }
+      break;
+    case type_cname:
+      {
+        dns::cname_resource*  cnamePtr = new dns::cname_resource(preamble);
+        cnamePtr->decode(buffer, offset_map);
+        ptr = shared_resource_base_t(cnamePtr);
+      }
+      break;
+               case type_soa:
+      {
+        dns::soa_resource*  soaPtr = new dns::soa_resource(preamble);
+        soaPtr->decode(buffer, offset_map);
+        ptr = shared_resource_base_t(soaPtr);
+      }
+      break;
+               case type_ptr:
+      {
+        dns::ptr_resource*  ptrPtr = new dns::ptr_resource(preamble);
+        ptrPtr->decode(buffer, offset_map);
+        ptr = shared_resource_base_t(ptrPtr);
+      }
+      break;
+               case type_hinfo:
+      {
+        dns::hinfo_resource*  hinfoPtr = new dns::hinfo_resource(preamble);
+        hinfoPtr->decode(buffer, offset_map);
+        ptr = shared_resource_base_t(hinfoPtr);
+      }
+      break;
+               case type_mx:
+      {
+        dns::mx_resource*  mxPtr = new dns::mx_resource(preamble);
+        mxPtr->decode(buffer, offset_map);
+        ptr = shared_resource_base_t(mxPtr);
+      }
+      break;
+               case type_txt:
+      {
+        dns::txt_resource*  txtPtr = new dns::txt_resource(preamble);
+        txtPtr->decode(buffer, offset_map);
+        ptr = shared_resource_base_t(txtPtr);
+      }
+      break;
+    case type_a6:
+      {
+        dns::a6_resource* a6Ptr = new dns::a6_resource(preamble);
+        a6Ptr->decode(buffer, offset_map);
+        ptr = shared_resource_base_t(a6Ptr);
+      }
+      break;
+    case type_srv:
+      {
+        dns::srv_resource*  srvPtr = new dns::srv_resource(preamble);
+        srvPtr->decode(buffer, offset_map);
+        ptr = shared_resource_base_t(srvPtr);
+      }
+      break;
+    default:
+      {
+        // An unknown record. Save the data and move on.
+        unknown_resource *unkPtr = new unknown_resource(preamble);
+        unkPtr->decode(buffer, offset_map);
+        ptr = shared_resource_base_t(unkPtr);
+      }
+      break;
+    }
+
+    return ptr;
+  }
+};
+
+    } // namespace dns
+  } // namespace net
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_NET_DNS_HPP
diff --git a/lib/boost-net-dns/boost/net/dns_cache.hpp b/lib/boost-net-dns/boost/net/dns_cache.hpp
new file mode 100755 (executable)
index 0000000..18463a9
--- /dev/null
@@ -0,0 +1,388 @@
+//
+// dns_cache.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2008 Andreas Haberstroh (andreas at ibusy dot com)
+//
+// 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_NET_DNS_CACHE_HPP
+#define BOOST_NET_DNS_CACHE_HPP
+
+#include <vector>
+#include <boost/net/dns.hpp>
+
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/mem_fun.hpp>
+#include <boost/multi_index/member.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+#include <boost/multi_index/hashed_index.hpp>
+#include <boost/thread/mutex.hpp>
+
+using namespace boost::multi_index;
+using namespace boost::posix_time;
+using namespace std;
+
+namespace boost {
+  namespace net {
+    namespace dns {
+
+      /*!
+      Implementation for a simple DNS cache.
+      This cache uses two methods to remove a "stale" record.
+      
+        #1 - Expiration date
+        
+        #2 - Hit count
+        
+      */
+      class dns_cache_t
+      {
+      private:
+      
+        /*!
+        
+        */
+        struct dns_hasher\r
+        {\r
+        public:
+          /*!
+          */\r
+          static size_t query(const string& domain, const type_t rType, const class_t rClass = class_in)\r
+          {\r
+            boost::hash<string>            hString;\r
+            boost::hash<type_t>  hType;\r
+            boost::hash<class_t> hClass;\r
+            return size_t(hString(domain) + hType(rType) + hClass(rClass));\r
+          }\r
+
+          /*!
+          */
+          static std::size_t query(const request_base_t& dnr)\r
+          {\r
+            return query(dnr.domain(), dnr.rtype(), dnr.rclass());\r
+          }\r
+          \r
+          /*!
+          */
+          static std::size_t query(const shared_resource_base_t& dnr)\r
+          {\r
+            return query(dnr->domain(), dnr->rtype(), dnr->rclass());\r
+          }\r
+\r
+          /*!
+          */
+          static std::size_t record(const shared_resource_base_t& rr)\r
+          {\r
+            std::size_t hashCode(dns_hasher::query(rr));\r
+\r
+            boost::hash<uint32_t>     h32;\r
+            boost::hash<string>       hString;\r
+\r
+            switch( rr->rtype() )\r
+            {\r
+            case type_a:\r
+              hashCode += h32( ((a_resource*)rr.get())->address().to_ulong() );\r
+              break;\r
+            case type_ns:\r
+              hashCode += hString( ((ns_resource*)rr.get())->nameserver() );\r
+              break;\r
+            case type_cname:
+              hashCode += hString( ((cname_resource*)rr.get())->canonicalname() );
+              break;
+            case type_soa:
+              hashCode += h32( ((soa_resource*)rr.get())->serial_number() );
+              break;
+            case type_ptr:
+              hashCode += hString( ((ptr_resource*)rr.get())->pointer() );
+              break;
+            case type_mx:
+              hashCode += hString( ((mx_resource*)rr.get())->exchange() ) + h32( ((mx_resource*)rr.get())->preference() );
+              break;
+
+            case type_a6:
+            case type_srv:
+              break;
+              
+            case type_none:
+            case type_hinfo:
+            case type_txt:
+            case type_axfr:
+            case type_all:
+              break;
+            
+            }\r
+
+            return hashCode;\r
+          }\r
+        };
+
+        /*!
+        */
+        struct rr_cache\r
+        {\r
+          size_t      _rHash;\r
+          size_t      _qHash;
+          size_t      _dHash;\r
+          uint32_t    _hits;\r
+          time_period _expirationTime;\r
+          ptime       _timeRetrieved;
+          bool        _perm;
+          \r
+          shared_resource_base_t record;\r
+
+          /*!
+          */
+          rr_cache(const shared_resource_base_t& rr, const bool perm)\r
+          : _hits(0),
+            _expirationTime(second_clock::local_time(), seconds(rr->ttl())),
+            _timeRetrieved(second_clock::local_time()),
+            _perm(perm),
+            record(rr)\r
+          {
+            _rHash = dns_hasher::record(rr);\r
+            _qHash = dns_hasher::query(rr);
+            
+            boost::hash<string> hString;\r
+            _dHash = hString(record.get()->domain());
+          }\r
+\r
+          /*!
+          */
+          virtual ~rr_cache()\r
+          {
+          }\r
+
+          /*!
+          */
+          bool expired() const
+          {
+            if( _perm )
+              return false;
+              
+            ptime nowTime = second_clock::local_time();
+            return (!_expirationTime.contains(nowTime));
+          }
+          
+          uint32_t hits() const
+          {
+            if( _perm )
+              return 0xFFFFFFFF;
+
+            return _hits;
+          }
+
+        };      
+        /*!
+        */
+        typedef shared_ptr<rr_cache>  shared_rr_cache;\r
+\r
+        struct by_d{};
+        struct by_r{};\r
+        struct by_q{};\r
+        struct by_hits{};
+        struct by_ttl{};\r
+#if !defined(GENERATING_DOCUMENTATION)\r
+        /*!
+        */
+        typedef boost::multi_index::multi_index_container<\r
+          shared_rr_cache,\r
+          boost::multi_index::indexed_by<\r
+            boost::multi_index::hashed_non_unique<
+              boost::multi_index::tag<by_d>, 
+              boost::multi_index::member<rr_cache, std::size_t, &rr_cache::_dHash>
+            >,\r
+            boost::multi_index::hashed_unique<
+              boost::multi_index::tag<by_r>, 
+              boost::multi_index::member<rr_cache, std::size_t, &rr_cache::_rHash>
+            >,\r
+            boost::multi_index::hashed_non_unique<
+              boost::multi_index::tag<by_q>, 
+              boost::multi_index::member<rr_cache, std::size_t, &rr_cache::_qHash>
+            >,
+            boost::multi_index::ordered_non_unique< 
+              boost::multi_index::tag<by_hits>, 
+              boost::multi_index::const_mem_fun<rr_cache, uint32_t, &rr_cache::hits> 
+            >,
+            boost::multi_index::ordered_non_unique< 
+              boost::multi_index::tag<by_ttl>, 
+              boost::multi_index::const_mem_fun<rr_cache, bool, &rr_cache::expired> 
+            >
+          >\r
+        > rr_container_t;\r
+#endif
+        typedef rr_container_t::index<by_d>::type::iterator     d_iter_t;
+        typedef rr_container_t::index<by_r>::type::iterator     r_iter_t;\r
+        typedef rr_container_t::index<by_q>::type::iterator     q_iter_t;\r
+        typedef rr_container_t::index<by_hits>::type::iterator  hits_iter_t;\r
+        typedef rr_container_t::index<by_ttl>::type::iterator   ttl_iter_t;\r
+
+        ///
+        rr_container_t  _cache;
+        ///
+        const uint32_t  _max_elements;
+        ///
+        boost::mutex    _mutex;
+
+      public:
+        /*!
+        */
+        dns_cache_t()
+          : _max_elements(16)
+        {
+        }
+
+        /*!
+        */
+        bool exists(const question& q)
+        {
+          boost::mutex::scoped_lock scopeLock(_mutex);
+          
+          size_t qHash = dns_hasher::query(q);
+
+          q_iter_t rrIter = _cache.get<by_q>().find(qHash);
+          if( rrIter == _cache.get<by_q>().end() )
+            return false;\r
+
+          return true;
+        }
+        
+        /*!
+        */
+        bool exists(const std::string& domain, const type_t rType)
+        {
+          question q(domain,rType);
+          return exists(q);
+        }
+
+        /*!
+        */
+        rr_list_t get(const question& q)
+        {
+          boost::mutex::scoped_lock scopeLock(_mutex);
+
+          rr_list_t retList; 
+        
+          std::pair<q_iter_t,q_iter_t> rrIter = _cache.get<by_q>().equal_range(dns_hasher::query(q));    
+          while( rrIter.first != rrIter.second )
+          {
+            (*rrIter.first)->_hits++;
+            (*rrIter.first)->_timeRetrieved = second_clock::local_time();
+           
+            retList.push_back( (*rrIter.first)->record );
+            rrIter.first++;
+          }
+          
+          return retList;
+        }
+        
+        /*!
+        */
+        rr_list_t get(const std::string& domain, const type_t rType)
+        {
+          question q(domain,rType);
+          return get(q);
+        }
+        
+        /*!
+        */
+        void add(const shared_resource_base_t& rr, const bool perm = false)
+        {
+          if( _cache.size() > _max_elements )
+            reserve(4, *rr.get() );
+
+          boost::mutex::scoped_lock scopeLock(_mutex);
+          shared_rr_cache rrItem(new rr_cache(rr,perm));
+          _cache.insert(rrItem);
+        }
+
+        /*!
+        */
+        void reserve(const size_t reserve_count, request_base_t& q)
+        {
+          size_t  cacheSize = _cache.size();
+          if( cacheSize < (_max_elements - reserve_count) )
+            return ;
+          
+          expiredCleanup(reserve_count, q);
+          cacheSize = _cache.size();
+          if( reserve_count < (_max_elements - _cache.size()) )
+            return;
+
+          uint32_t  lowMark(0);
+          while( reserve_count > (_max_elements - _cache.size()) )
+            lowestHitCleanup(reserve_count, q, lowMark++);
+        }
+          
+        /*!
+        */
+        void show_cache()
+        {
+          d_iter_t  iter;
+          
+          for( iter = _cache.get<by_d>().begin(); iter != _cache.get<by_d>().end(); ++iter )
+          {
+            cout << "+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+" << endl
+                 << "          Hits: " << (*iter)->_hits << endl
+                 << "   Lifetime at: " << to_simple_string((*iter)->_expirationTime) << endl
+                 << "Last Retrieved: " << to_simple_string((*iter)->_timeRetrieved) << endl;
+            debug::dump_record(cout, (*iter)->record.get() );
+          }
+        }
+        
+      private:
+        /*!
+        */
+        int expiredCleanup(size_t reserve_count, request_base_t& q)
+        {
+          boost::mutex::scoped_lock scopeLock(_mutex);
+          int count(0);
+          std::pair<ttl_iter_t,ttl_iter_t> range_iter;
+          for( 
+            range_iter = _cache.get<by_ttl>().equal_range(true);
+            range_iter.first != range_iter.second;
+            ++range_iter.first, ++count )
+          {
+            if( q.domain() != (*range_iter.first)->record->domain() )
+            {
+              _cache.get<by_ttl>().erase(range_iter.first);
+              if( --reserve_count == 0 )
+                break;
+            }
+          }
+          
+          return count;
+        }
+          
+        /*!
+        */
+        uint32_t lowestHitCleanup(size_t reserve_count, request_base_t& q, uint32_t lowMark = 0)
+        {
+          boost::mutex::scoped_lock scopeLock(_mutex);
+          int count(0);
+          
+          std::pair<hits_iter_t,hits_iter_t> range_iter;
+          for( 
+            range_iter = _cache.get<by_hits>().equal_range(lowMark);
+            range_iter.first != range_iter.second;
+            ++range_iter.first, ++count )
+          {
+            if( q.domain() != (*range_iter.first)->record->domain() )
+            {
+              _cache.get<by_hits>().erase(range_iter.first);
+              if( --reserve_count == 0 )
+                break;
+            }
+          }
+          
+          return count;
+        }
+      };
+
+    } // namespace dns
+  } // namespace net
+} // namespace boost
+
+#endif  // BOOST_NET_DNS_CACHE_HPP
diff --git a/lib/boost-net-dns/boost/net/dns_debug.hpp b/lib/boost-net-dns/boost/net/dns_debug.hpp
new file mode 100755 (executable)
index 0000000..b3ec92d
--- /dev/null
@@ -0,0 +1,293 @@
+//
+// dns_debug.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 1998-2006 Andreas Haberstroh (andreas at ibusy dot com)
+//
+// 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_NET_DNS_DEBUG_HPP
+#define BOOST_NET_DNS_DEBUG_HPP
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/net/dns.hpp>
+
+namespace boost {
+  namespace net {
+    namespace dns {
+
+/*!
+The debug class offers some quick functions used for debuging DNS records
+*/
+class debug
+{
+public:
+  /*!
+  Returns a string representation of a class_t type.
+  \param qclass Class to retrieve the string name of
+  \returns  String name of the class
+  */
+  static const char *get_class_string(const dns::class_t qclass)\r
+  {\r
+\r
+         switch( qclass )\r
+         {\r
+    case dns::class_in:\r
+                 return "IN";\r
+\r
+         case dns::class_cs:\r
+                 return "CSNET";\r
+\r
+         case dns::class_ch:\r
+                 return "CHAOS";\r
+\r
+         case dns::class_hs:\r
+                 return "Hesiod";\r
+\r
+         case dns::class_all:\r
+                 return "All";\r
+\r
+    case dns::class_none:\r
+      return "!CLASS NOT SET!";\r
+      break;\r
+    }\r
+\r
+         return "!INVALID CLASS!";\r
+  }\r
+\r
+  /*!
+  Returns a string representation of a type_t type.
+  \param qtype Type to retrieve the string name of
+  \returns  String name of the type
+  */
+  static const char *get_type_string(const dns::type_t qtype)\r
+  {\r
+         switch( qtype )\r
+         {\r
+    case dns::type_a:\r
+                 return "A";\r
+\r
+         case dns::type_ns:\r
+                 return "NS";\r
+\r
+         case dns::type_cname:\r
+                 return "CNAME";\r
+\r
+         case dns::type_soa:\r
+                 return "SOA";\r
+\r
+         case dns::type_ptr:\r
+                 return "PTR";\r
+\r
+         case dns::type_hinfo:\r
+                 return "HINFO";\r
+\r
+         case dns::type_mx:\r
+                 return "MX";\r
+\r
+         case dns::type_txt:\r
+                 return "TXT";\r
+\r
+    case dns::type_a6:
+      return "AAAA";
+\r
+    case dns::type_srv:
+      return "SRV";
+
+         case dns::type_axfr:
+      return "AXFR";
+
+         case dns::type_all:
+      return "ALL";
+\r
+         case dns::type_none:
+      return "!TYPE NOT SET!";
+    }\r
+\r
+         return "!INVALID TYPE!";\r
+  }\r
+\r
+  static void dump_a(ostream& strm, dns::resource_base_t* Ptr)\r
+  {\r
+         strm
+               << ((dns::a_resource*)Ptr)->domain() << "\t" \r
+                         << ((dns::a_resource*)Ptr)->ttl() << "\t" \r
+                         << get_class_string(((dns::a_resource*)Ptr)->rclass()) << "\t"\r
+                         << get_type_string(((dns::a_resource*)Ptr)->rtype()) << "\t"\r
+                         << ((dns::a_resource*)Ptr)->address().to_string() << endl;\r
+  }\r
+\r
+  static void dump_a6(ostream& strm, dns::resource_base_t* Ptr)\r
+  {\r
+    try\r
+    {\r
+       strm    
+             << ((dns::a6_resource*)Ptr)->domain() << "\t" \r
+                         << ((dns::a6_resource*)Ptr)->ttl() << "\t" \r
+                         << get_class_string(((dns::a6_resource*)Ptr)->rclass()) << "\t"\r
+                         << get_type_string(((dns::a6_resource*)Ptr)->rtype()) << "\t"\r
+                         << ((dns::a6_resource*)Ptr)->address().to_string() << endl;\r
+    }\r
+    catch(boost::system::error_code& ec)\r
+    {\r
+      strm << ec.message() << endl;\r
+    }\r
+  }\r
+\r
+  static void dump_ns(ostream& strm, dns::resource_base_t* Ptr)\r
+  {\r
+         strm
+             << ((dns::ns_resource*)Ptr)->domain() << "\t" \r
+                         << ((dns::ns_resource*)Ptr)->ttl() << "\t" \r
+                         << get_class_string(((dns::ns_resource*)Ptr)->rclass()) << "\t"\r
+                         << get_type_string(((dns::ns_resource*)Ptr)->rtype()) << "\t"\r
+                         << ((dns::ns_resource*)Ptr)->nameserver() << endl;\r
+  }\r
+\r
+  static void dump_mx(ostream& strm, dns::resource_base_t* Ptr)\r
+  {\r
+         strm
+                 << ((dns::mx_resource*)Ptr)->domain() << "\t" \r
+                 << ((dns::mx_resource*)Ptr)->ttl() << "\t" \r
+                 << get_class_string(((dns::mx_resource*)Ptr)->rclass()) << "\t"\r
+                 << get_type_string(((dns::mx_resource*)Ptr)->rtype()) << "\t"\r
+                 << ((dns::mx_resource*)Ptr)->preference() << "\t" \r
+                 << ((dns::mx_resource*)Ptr)->exchange() << endl;\r
+  }\r
+\r
+  static void dump_soa(ostream& strm, dns::resource_base_t* Ptr)\r
+  {\r
+         strm
+      << ((dns::soa_resource*)Ptr)->domain() << "\t" \r
+      << ((dns::soa_resource*)Ptr)->ttl() << "\t" \r
+      << "SOA\t" \r
+      << get_class_string(((dns::soa_resource*)Ptr)->rclass()) << "\t"\r
+      << get_type_string(((dns::soa_resource*)Ptr)->rtype()) << "\t"\r
+      << ((dns::soa_resource*)Ptr)->master_name() << "\t"\r
+      << ((dns::soa_resource*)Ptr)->responsible_name() << "\t"\r
+      << ((dns::soa_resource*)Ptr)->serial_number() << "\t"\r
+      << ((dns::soa_resource*)Ptr)->refresh() << "\t"\r
+      << ((dns::soa_resource*)Ptr)->retry() << "\t"\r
+      << ((dns::soa_resource*)Ptr)->expire() << "\t"\r
+      << ((dns::soa_resource*)Ptr)->minttl() << endl;\r
+  }\r
+\r
+  static void dump_cname(ostream& strm, dns::resource_base_t* Ptr)\r
+  {\r
+    strm
+                 << ((dns::cname_resource*)Ptr)->domain() << "\t" \r
+                 << ((dns::cname_resource*)Ptr)->ttl() << "\t" \r
+                 << get_class_string(((dns::cname_resource*)Ptr)->rclass()) << "\t"\r
+                 << get_type_string(((dns::cname_resource*)Ptr)->rtype()) << "\t"\r
+                 << ((dns::cname_resource*)Ptr)->canonicalname() << endl;\r
+  }\r
+\r
+  static void dump_hinfo(ostream& strm, dns::resource_base_t* Ptr)\r
+  {\r
+         strm
+                 << ((dns::hinfo_resource*)Ptr)->domain() << "\t" \r
+                 << ((dns::hinfo_resource*)Ptr)->ttl() << "\t" \r
+                 << get_class_string(((dns::hinfo_resource*)Ptr)->rclass()) << "\t"\r
+                 << get_type_string(((dns::hinfo_resource*)Ptr)->rtype()) << "\t"\r
+                 << ((dns::hinfo_resource*)Ptr)->cpu() << "\t"\r
+      << ((dns::hinfo_resource*)Ptr)->os() << endl;\r
+  }\r
+\r
+  static void dump_text(ostream& strm, dns::resource_base_t* Ptr)\r
+  {\r
+         strm
+                 << ((dns::txt_resource*)Ptr)->domain() << "\t" \r
+                 << ((dns::txt_resource*)Ptr)->ttl() << "\t" \r
+                 << get_class_string(((dns::txt_resource*)Ptr)->rclass()) << "\t"\r
+                 << get_type_string(((dns::txt_resource*)Ptr)->rtype()) << "\t"\r
+                 << ((dns::txt_resource*)Ptr)->text() << endl;\r
+  }\r
+\r
+  static void dump_ptr(ostream& strm, dns::resource_base_t* Ptr)\r
+  {\r
+         strm
+                 << ((dns::ptr_resource*)Ptr)->domain() << "\t" \r
+                 << ((dns::ptr_resource*)Ptr)->ttl() << "\t" \r
+                 << get_class_string(((dns::ptr_resource*)Ptr)->rclass()) << "\t"\r
+                 << get_type_string(((dns::ptr_resource*)Ptr)->rtype()) << "\t"\r
+                 << ((dns::ptr_resource*)Ptr)->pointer() << endl;\r
+  }\r
+\r
+  static void dump_srv(ostream& strm, dns::resource_base_t* Ptr)\r
+  {\r
+         strm
+                 << ((dns::srv_resource*)Ptr)->domain() << "\t" \r
+                 << ((dns::srv_resource*)Ptr)->ttl() << "\t" \r
+                 << get_class_string(((dns::srv_resource*)Ptr)->rclass()) << "\t"\r
+                 << get_type_string(((dns::srv_resource*)Ptr)->rtype()) << "\t"\r
+                 << ((dns::srv_resource*)Ptr)->priority() << "\t"\r
+                 << ((dns::srv_resource*)Ptr)->weight() << "\t"\r
+      << ((dns::srv_resource*)Ptr)->port() << "\t"\r
+      << ((dns::srv_resource*)Ptr)->targethost() << endl;\r
+  }\r
+\r
+  /*!
+  Used to dump out a record to a ostream object.
+  \param strm Ostream to write to
+  \param ptr Resource base object to dump
+  */
+  static void dump_record(ostream& strm, dns::resource_base_t * ptr )\r
+  {\r
+      switch( ptr->rtype() )\r
+                 {\r
+      case dns::type_a:\r
+                         dump_a(strm, ptr);\r
+                         break;\r
+\r
+                 case dns::type_ns:\r
+                         dump_ns(strm, ptr);\r
+                         break;\r
+\r
+                 case dns::type_cname:\r
+                         dump_cname(strm, ptr);\r
+                         break;\r
+\r
+                 case dns::type_soa:\r
+                         dump_soa(strm, ptr);\r
+                         break;\r
+\r
+                 case dns::type_ptr:\r
+                         dump_ptr(strm, ptr);\r
+                         break;\r
+\r
+                 case dns::type_hinfo:\r
+                         dump_hinfo(strm, ptr);\r
+                         break;\r
+\r
+                 case dns::type_mx:\r
+                         dump_mx(strm, ptr);\r
+                         break;\r
+\r
+                 case dns::type_txt:\r
+                         dump_text(strm, ptr);\r
+                         break;\r
+\r
+                 case dns::type_a6:\r
+                         dump_a6(strm, ptr);\r
+                         break;\r
+\r
+                 case dns::type_srv:\r
+                         dump_srv(strm, ptr);\r
+                         break;\r
+\r
+                 default:\r
+                         strm << "Unhandled record type!" << endl;\r
+                         break;\r
+                 }\r
+  }
+};
+
+    } // namespace dns
+  } // namespace net
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_NET_DNS_DEBUG_HPP
diff --git a/lib/boost-net-dns/boost/net/dns_resolver.hpp b/lib/boost-net-dns/boost/net/dns_resolver.hpp
new file mode 100755 (executable)
index 0000000..3a13b23
--- /dev/null
@@ -0,0 +1,22 @@
+//
+// dns_resolver.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2008 Andreas Haberstroh (andreas at ibusy dot com)
+//
+// 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_NET_DNS_RESOLVER_HPP
+#define BOOST_NET_DNS_RESOLVER_HPP
+
+#include <boost/asio.hpp>
+#include <boost/net/dns.hpp>
+#include <boost/net/dns_debug.hpp>
+#include <boost/net/dns_cache.hpp>
+#include <boost/net/network_array.hpp>
+#include <boost/net/impl/dns_resolver_impl.hpp>
+#include <boost/net/basic_dns_resolver_service.hpp>
+#include <boost/net/basic_dns_resolver.hpp>
+
+#endif  //  BOOST_NET_DNS_RESOLVER_HPP
diff --git a/lib/boost-net-dns/boost/net/impl/dns_resolver_impl.hpp b/lib/boost-net-dns/boost/net/impl/dns_resolver_impl.hpp
new file mode 100755 (executable)
index 0000000..903f1a2
--- /dev/null
@@ -0,0 +1,547 @@
+//
+// dns_resolver_impl.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2008 Andreas Haberstroh (andreas at ibusy dot com)
+//
+// 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_NET_DNS_RESOLVER_IMPL_HPP
+#define BOOST_NET_DNS_RESOLVER_IMPL_HPP
+
+#include <vector>
+
+#include <boost/net/dns_cache.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/random.hpp>
+#include <boost/thread/detail/singleton.hpp>
+
+using namespace boost::multi_index;
+
+namespace boost {
+  namespace net {
+    namespace dns {
+
+/// Single instance of the dns cache
+typedef boost::detail::thread::singleton<net::dns::dns_cache_t> dns_cache_object;
+
+class dns_resolver_impl \r
+{
+private:
+  /// Outbound DNS request buffer 
+  typedef vector<ip::udp::endpoint> ep_vector_t;
+
+  class dns_handler_base
+  {
+  public:
+    dns_handler_base()
+    {
+    }
+    
+    virtual ~dns_handler_base()
+    {
+    }
+
+    virtual void invoke(io_service& ios, const shared_resource_base_t& record, const boost::system::error_code& ec)
+    {
+    }
+  };
+  
+  typedef shared_ptr<dns_handler_base>  dns_handler_base_t;
+
+  /// Handler to wrap asynchronous callback function
+  template <typename Handler>
+  class dns_handler : public dns_handler_base
+  {
+  public:
+    dns_handler(Handler h)
+    : dns_handler_base(),
+      handler_(h)
+    {
+    }
+
+    virtual ~dns_handler()
+    {
+    }
+
+    virtual void invoke(io_service& ios, const shared_resource_base_t& record, const boost::system::error_code& ec)
+    {
+      ios.post( 
+        boost::asio::detail::bind_handler(handler_, record, ec)
+      )
+      ;
+    }
+
+  private:
+    Handler handler_;
+  };
+
+  /*!
+  DNS Query structure  
+  */
+  struct dns_query_t
+  {
+    dns_query_t(const net::dns::question& q)
+    : _query_start(posix_time::second_clock::local_time(), posix_time::seconds(30)),
+      _query_sent(posix_time::second_clock::local_time(), posix_time::seconds(2))
+    {
+      _question = q;
+//      _qbuffer = shared_ptr<net::network_buffer_t>(new net::network_buffer_t(_mbuffer.data(), _mbuffer.size()));
+    }
+    
+    dns_query_t(const dns_query_t& o)
+    : _query_start(posix_time::time_period(o._query_start.begin(), o._query_start.last())),
+      _query_sent(posix_time::time_period(o._query_sent.begin(), o._query_sent.last()))
+    {
+      operator=(o);
+    }
+
+    virtual ~dns_query_t()
+    {
+    }
+    
+    dns_query_t& operator=(const dns_query_t& o)
+    {
+      _question_id = o._question_id;
+      _dns = o._dns;
+      _mbuffer = o._mbuffer;
+  //    _qbuffer = o._qbuffer;
+      _question = o._question;
+      _completion_callback = o._completion_callback;
+      _query_start = posix_time::time_period(o._query_start.begin(), o._query_start.last());
+      _query_sent = posix_time::time_period(o._query_sent.begin(), o._query_sent.last());
+      return *this;
+    }
+
+    /// Question ID
+    uint16_t        _question_id;
+    
+    /// Domain Name Server Address to send request to
+    ip::udp::endpoint _dns;
+
+    /// DNS Query Buffer
+    dns_buffer_t          _mbuffer;
+//    shared_dns_buffer_t   _qbuffer;
+
+    /// DNS Query question
+    net::dns::question                _question;
+    
+    /// DNS Completion handler
+    dns_handler_base_t                _completion_callback;
+    
+    /// Time period the request is good for
+    posix_time::time_period     _query_start;
+            
+    /// Time period which the last request was sent
+    posix_time::time_period     _query_sent;
+    
+    bool operator<( const uint16_t& id ) const 
+    { 
+      return _question_id < id; 
+    }
+    
+    bool expired() const
+    {
+      posix_time::ptime nowTime = posix_time::second_clock::local_time();
+      return !_query_start.contains(nowTime);
+    }
+
+    bool resend() const
+    {
+      posix_time::ptime nowTime = posix_time::second_clock::local_time();
+      return _query_sent.contains(nowTime);
+    }
+  };
+
+  typedef shared_ptr<dns_query_t>   shared_dq_t;
+
+  struct by_question_id{};
+  struct by_expired{};
+  struct by_resend{};
+#if !defined(GENERATING_DOCUMENTATION)
+  typedef 
+  multi_index_container<
+    shared_dq_t,
+    indexed_by<
+      ordered_non_unique< 
+        tag<by_resend>,
+        const_mem_fun<dns_query_t, bool, &dns_query_t::resend> 
+      >,
+      ordered_non_unique< 
+        tag<by_expired>,
+        const_mem_fun<dns_query_t, bool, &dns_query_t::expired> 
+      >,
+      ordered_non_unique< 
+        tag<by_question_id>, 
+        member<dns_query_t, uint16_t, &dns_query_t::_question_id> 
+      >
+    >
+  > query_container_t;
+#endif
+  typedef query_container_t::index<by_question_id>::type::iterator  question_id_iterator_t;
+  typedef query_container_t::index<by_expired>::type::iterator      expired_iterator_t;
+  typedef query_container_t::index<by_resend>::type::iterator       resend_iterator_t;
+
+
+  io_service&       _ios;
+  deadline_timer    _timer;
+  ip::udp::socket   _socket;
+  ep_vector_t       _dnsList;
+  query_container_t _query_list;
+  boost::mutex      _resolver_mutex;
+  mutable bool      _outstanding_read;
+  boost::mt19937    _rng;
+\r
+public: 
+  dns_resolver_impl(io_service& ios)
+    : _ios(ios),
+      _timer(_ios),  
+      _socket(_ios),
+      _outstanding_read(false)
+  {
+  }
+    \r
+       void destroy() \r
+       { \r
+       }
+
+  void add_nameserver(ip::address addr)
+  {
+    ip::udp::endpoint endpoint(addr, 53);
+    _dnsList.push_back(endpoint);
+  }
+  
+  void cancel()
+  {
+    _socket.cancel();
+  }
+
+  template<typename CallbackHandler>
+  void async_resolve(const net::dns::question & question, CallbackHandler handler)
+  {
+    if( dns_cache_object::instance().exists(question) )
+    {
+      boost::system::error_code callbackError;
+      dns_handler<CallbackHandler>  caller(handler);
+    
+      rr_list_t record_list = dns_cache_object::instance().get(question);
+      for( rr_list_t::iterator iter = record_list.begin();
+            iter != record_list.end();
+            ++iter )
+      {
+        caller.invoke(_ios, (*iter), callbackError );
+      }
+    }
+    else
+    {
+      boost::mutex::scoped_lock scopeLock(_resolver_mutex);
+      if( !_socket.is_open() )
+      {
+        _socket.open(ip::udp::v4());
+        _socket.bind(ip::udp::endpoint(ip::udp::v4(), 0));
+      }
+      
+      _timer.expires_from_now(posix_time::seconds(2));
+      _timer.async_wait(
+        boost::bind(
+          &dns_resolver_impl::handle_timeout, 
+          this,
+          boost::asio::placeholders::error
+        )
+      );
+      
+      net::dns::message  qmessage(question);
+
+      // set a few defaults for a message
+      qmessage.recursive(true);
+      qmessage.action(net::dns::message::query);
+      qmessage.opcode(net::dns::message::squery);
+
+      // make our message id unique
+      uint16_t quid( (uint16_t)_rng() );
+      
+      for( ep_vector_t::iterator iter = _dnsList.begin(); iter != _dnsList.end(); ++iter)
+      {
+        shared_dq_t dq = shared_dq_t(new dns_query_t(question));
+
+        dq->_question_id = (uint16_t)quid;
+        dq->_dns = *iter;
+        dq->_completion_callback = shared_ptr<dns_handler<CallbackHandler> >(new dns_handler<CallbackHandler>(handler));
+
+        qmessage.id( dq->_question_id );
+        qmessage.encode( dq->_mbuffer );
+
+        _query_list.insert(dq);
+        send_request(dq);
+      }
+    }
+  }
+
+  template<typename CallbackHandler>
+  void async_resolve(const string & domain, const net::dns::type_t rrtype, CallbackHandler handler)
+  {
+    net::dns::question question(domain, rrtype);
+    async_resolve(question, handler);
+  }
+
+  boost::asio::io_service & get_io_service()
+  {
+    return _ios;
+  }
+
+  rr_list_t resolve(const net::dns::question & question, boost::system::error_code & ec)
+  {
+    rr_list_t _list;
+    return _list;
+  }
+  
+  rr_list_t resolve(const net::dns::question & question)
+  {
+    shared_rr_list_t _list(new rr_list_t);
+    
+    io_service        thisIos;
+    dns_resolver_impl thisResolve(thisIos);
+    thisResolve._dnsList = _dnsList;
+
+    thisResolve.async_resolve(
+      question, 
+      bind(
+        &dns_resolver_impl::blocking_callback, 
+        &thisResolve, 
+        _list, _1, _2
+      )
+    );
+    
+    thisIos.run();
+    
+    return *_list.get();
+  }
+  
+  rr_list_t resolve(const string & domain, const net::dns::type_t rrtype)
+  {
+    net::dns::question question(domain, rrtype);
+    return resolve(question);
+  }
+
+  rr_list_t resolve(const string & domain, const net::dns::type_t rrtype, boost::system::error_code & ec)
+  {
+    rr_list_t _list;
+    return _list;
+  }
+  
+private:
+  void send()
+  {
+    boost::mutex::scoped_lock scopeLock(_resolver_mutex);
+    
+    question_id_iterator_t iter;
+    for( iter = _query_list.get<by_question_id>().begin(); iter != _query_list.get<by_question_id>().end(); ++iter)
+    {
+      _ios.post(
+        bind(
+          &dns_resolver_impl::send_request, 
+          this,
+          (*iter)
+        )
+      );
+    }
+  }
+
+  void send_request(shared_dq_t& dq)
+  {
+//    cout << "send_request: " << dq->_dns.address().to_string() << endl;
+    _socket.async_send_to(
+      boost::asio::buffer(
+        dq->_mbuffer.data(), 
+        dq->_mbuffer.length()
+        ), 
+      dq->_dns,
+      boost::bind(
+        &dns_resolver_impl::handle_send, 
+        this, 
+        dq,
+        boost::asio::placeholders::error,
+        boost::asio::placeholders::bytes_transferred
+        )
+      );
+  }
+  
+  void handle_send(shared_dq_t& dq, const boost::system::error_code& ec, size_t bytes_sent)
+  {
+    if (!ec || ec == boost::asio::error::message_size)
+    {
+      shared_dns_buffer_t rbuffer(new dns_buffer_t );
+      
+      _socket.async_receive(
+        boost::asio::buffer( 
+          *(rbuffer.get()) 
+        ),
+        boost::bind(
+          &dns_resolver_impl::handle_recv, 
+          this, 
+          rbuffer,
+          boost::asio::placeholders::error,
+          boost::asio::placeholders::bytes_transferred
+        )
+      );
+    }
+  }
+
+  void handle_recv(shared_dns_buffer_t  inBuffer, const boost::system::error_code& ec, std::size_t bytes_transferred)
+  {
+    boost::mutex::scoped_lock scopeLock(_resolver_mutex);
+    _outstanding_read = false;
+    
+    if( !ec && bytes_transferred ) // || ec == boost::asio::error::message_size)
+    {
+      inBuffer.get()->length(bytes_transferred);
+
+      net::dns::message  tmpMessage;
+      
+      uint16_t  qid;
+      inBuffer.get()->get(qid);
+      
+      std::pair<question_id_iterator_t,question_id_iterator_t> range_iter;
+      range_iter = _query_list.get<by_question_id>().equal_range(qid);
+      if( range_iter.first == range_iter.second )
+        return ;
+      
+      question_id_iterator_t qiter = range_iter.first; 
+      
+      tmpMessage.decode( *inBuffer.get() );
+      boost::system::error_code callbackError;
+      if( tmpMessage.result() != net::dns::message::noerror )
+      {
+        callbackError = error::not_found;
+        shared_resource_base_t record;
+        (*qiter)->_completion_callback->invoke(_ios, record, callbackError);
+      }
+      else
+      {
+        net::dns::rr_list_t* records;
+        net::dns::rr_list_t::iterator  iter;
+
+        // Grab all the records, we'll probably need more info for additional queries
+        if( tmpMessage.additionals()->size() )
+        {
+          records = tmpMessage.additionals();
+          dns_cache_object::instance().reserve( records->size(), (*qiter)->_question );
+          for( iter = records->begin(); iter != records->end(); ++iter )
+            dns_cache_object::instance().add( (*iter) );
+        }
+      
+        if( tmpMessage.authorites()->size() )
+        {
+          records = tmpMessage.authorites();
+          dns_cache_object::instance().reserve( records->size(), (*qiter)->_question );
+          for( iter = records->begin(); iter != records->end(); ++iter )
+            dns_cache_object::instance().add( (*iter) );
+        }
+      
+        if( tmpMessage.answers()->size() )
+        {
+          records = tmpMessage.answers();
+          dns_cache_object::instance().reserve( records->size(), (*qiter)->_question );
+          for( iter = records->begin(); iter != records->end(); ++iter )
+          {
+            dns_cache_object::instance().add( (*iter) );
+            (*qiter)->_completion_callback->invoke(_ios, (*iter), callbackError);
+          }
+        }
+      }
+
+      _query_list.get<by_question_id>().erase(range_iter.first, range_iter.second);  
+      if( !_query_list.size() )
+      {
+        _timer.cancel();
+        _socket.close();
+      }
+    }
+    else if (ec == error::operation_aborted)
+    {
+      inBuffer.get()->length(bytes_transferred);
+      
+      uint16_t  qid;
+      inBuffer.get()->get(qid);
+      
+      std::pair<question_id_iterator_t,question_id_iterator_t> range_iter;
+      range_iter = _query_list.get<by_question_id>().equal_range(qid);
+
+      if( range_iter.first != range_iter.second )
+      {
+        shared_resource_base_t  record;
+        (*range_iter.first)->_completion_callback->invoke(_ios, record, error::operation_aborted);
+      }
+      
+      _query_list.get<by_question_id>().erase(range_iter.first, range_iter.second);  
+      if( !_query_list.size() )
+      {
+        _timer.cancel();
+        _socket.close();
+      }
+    }    
+    else
+    {
+    }
+  }
+
+  void handle_timeout(const boost::system::error_code& ec)
+  {
+    if( !ec && ec != error::operation_aborted )
+    {
+      // Lock the list so we can manipulate it
+      boost::mutex::scoped_lock scopeLock(_resolver_mutex);
+      
+      if( _query_list.size() )
+      {
+        shared_resource_base_t  record;
+        
+        expired_iterator_t  expired_iter = _query_list.get<by_expired>().find(true);
+        for( ; expired_iter != _query_list.get<by_expired>().end(); ++expired_iter )
+        {
+          if( (*expired_iter)->expired() )
+          {
+            (*expired_iter)->_completion_callback->invoke(_ios, record, error::timed_out);
+            _query_list.get<by_expired>().erase(expired_iter);
+          }
+        }
+      }
+      
+      if( _query_list.size() )
+      {
+        _timer.expires_from_now(posix_time::seconds(2));
+        _timer.async_wait(
+          boost::bind(
+            &dns_resolver_impl::handle_timeout, 
+            this,
+            boost::asio::placeholders::error
+          )
+        );
+        
+        _ios.post( bind(&dns_resolver_impl::send, this) );
+      }
+      else
+      {
+        _socket.close();
+      }
+    }
+  }
+
+  void blocking_callback(shared_rr_list_t& list, const shared_resource_base_t& record, const boost::system::error_code& ec)
+  {
+    // we're doing a asynch operation for a sync request
+    if( record )
+    {
+      list->push_back(record);
+    }
+    else
+      cout << "blocking_callback: " << ec.message() << endl;
+  }
+};
+
+    } // namespace dns
+  } // namespace net
+} // namespace boost
+
+#endif  // BOOST_NET_DNS_RESOLVER_IMPL_HPP
diff --git a/lib/boost-net-dns/boost/net/network_array.hpp b/lib/boost-net-dns/boost/net/network_array.hpp
new file mode 100755 (executable)
index 0000000..7a0b7ac
--- /dev/null
@@ -0,0 +1,483 @@
+//
+// network_array.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 1998-2006 Andreas Haberstroh (softwareace at yahoo dot com)
+//
+// 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_NET_NETWORK_ARRAY_HPP
+#define BOOST_NET_NETWORK_ARRAY_HPP
+
+// Our primary dependency is boost::asio. We can't live without it!
+#include <boost/asio/detail/push_options.hpp>
+
+#include <vector>
+#include <string>
+
+#include <boost/iterator.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/scoped_array.hpp>
+#include <boost/asio.hpp>
+#include <boost/array.hpp>
+
+using namespace std;
+using namespace boost;
+using namespace boost::asio;
+
+namespace boost {
+  namespace net {
+
+/**
+  The network_array class template provides a static size array of bytes 
+  that has accessors function to make getting and setting data network friendly.
+
+  Uses the Endian/Non-Endian transform functions, (i.e. htons,ntohs)
+
+  Derived from boost::array.
+ */
+template<std::size_t N>
+class network_array
+{
+private:
+  /// Array member
+  array<uint8_t, N> data_array;
+
+  /// Position in memory buffer for get/put
+  size_t  nap;  // acronym: network array position
+
+  /// Total size of memory buffer, not necessarily the N size of the buffer
+  size_t  nal; // acronym: network array length
+
+public:
+  /// Constructs an empty network_array 
+  /*
+
+  */
+  network_array()
+  : data_array(),
+    nap(0),
+    nal(0)
+  {
+    data_array.assign((uint8_t)0x00);
+  }
+
+  virtual ~network_array()
+  {}
+
+  /// Get & Set the position in the array
+  /**
+  @param p Sets the current caret position in the array. If left blank, it does not change the position, but only reports the position.
+  @return The current caret position in the array
+  */
+  size_t  position(const size_t p=N+1)
+  {
+    if( p != N + 1 )  nap = p;
+    return nap; 
+  }
+
+  /// Get & Set the length of data in the array
+  /**
+  This function does not change the size of the array, but only the reporting aspect of the amount of data contained in the array.
+  @param l Sets the data length in the array. If left blank, it does not change the length, but only reports the length.
+  @return The current length of the array
+  */
+  size_t  length(const size_t l=N+1)
+  {
+    if( l != N + 1 )  nal = l;
+    return nal; 
+  }    
+
+  /// Gets data from the array
+  /**
+  Gets a char from the array.
+  @param d Data to retrieve
+  @param p Position to retrieve data from. If left blank, will retrieve from the current caret position
+  @param incpos Increments the caret position in the array. If set to false the function acts like a peek
+  @return The amount of bytes retrieved from the array
+  */
+  size_t get(char & d, const size_t p=N+1, const bool incpos=true)
+  {
+    if( p != N+1 ) 
+    {
+      data_array.rangecheck(p);
+      position(p);
+    }
+
+    d = (char)data_array.elems[nap];
+    if( incpos ) nap += sizeof(d);
+
+    return sizeof(d);
+  }
+
+  /// Puts data into the array
+  /**
+   Puts a char into the array.
+   @param d Data to write into the array
+   @param p Position to write data to. If left blank, will write to the current caret position.
+   @param incpos Increments the caret position in the array. If set to false the function acts like a poke
+   @return The amount of bytes writen from the array
+   */
+  size_t put(const char d, const size_t p=N+1, const bool incpos=true)
+  {
+    if( p != N+1 ) 
+    {
+      data_array.rangecheck(p);
+      position(p);
+    }
+
+    data_array.elems[nap] = (uint8_t)d;
+    if( incpos )
+    {
+      nap += sizeof(d);
+      if( nap > nal )
+        nal += sizeof(d);
+    }
+
+    return sizeof(d);
+       }
+
+  /// Gets data from the array
+  /**
+   Gets a uint8_t from the array.
+   @param d Data to retrieve
+   @param p Position to retrieve data from. If left blank, will retrieve from the current caret position
+   @param incpos Increments the caret position in the array. If set to false the function acts like a peek
+   @return The amount of bytes retrieved from the array
+   */
+  size_t get(uint8_t & d, const size_t p=N+1, const bool incpos=true)
+  {
+    if( p != N+1 ) 
+    {
+      data_array.rangecheck(p);
+      position(p);
+    }
+
+    d = data_array.elems[nap];
+
+    if( incpos ) nap += sizeof(d);
+    return sizeof(d);
+  }
+
+  /// Puts data into the array
+  /**
+   Puts a uint8_t into the array.
+   @param d Data to write into the array
+   @param p Position to write data to. If left blank, will write to the current caret position.
+   @param incpos Increments the caret position in the array. If set to false the function acts like a poke
+   @return The amount of bytes writen from the array
+  */
+  size_t put(const uint8_t d, const size_t p=N+1, const bool incpos=true)
+  {
+    if( p != N+1 ) 
+    {
+      data_array.rangecheck(p);
+      position(p);
+    }
+
+    data_array.elems[nap] = d;
+
+    if( incpos )
+    {
+      nap += sizeof(d);
+      if( nap > nal )
+        nal += sizeof(d);
+    }
+
+    return sizeof(d);
+  }
+
+  /// Gets data from the array
+  /**
+   Gets a uint16_t from the array. The data returned is host friendly.
+   @param d Data to retrieve
+   @param p Position to retrieve data from. If left blank, will retrieve from the  current caret position
+   @param incpos Increments the caret position in the array. If set to false the function acts like a peek
+   @return The amount of bytes retrieved from the array
+   */
+  size_t get(uint16_t & d, const size_t p=N+1, const bool incpos=true)
+  {
+    if( p != N+1 ) 
+    {
+      data_array.rangecheck(p);
+      position(p);
+    }
+
+    d = ntohs( *((uint16_t *)&data_array.elems[nap]) );
+
+    if( incpos ) nap += sizeof(d);
+    return sizeof(d);
+  }
+
+  /// Puts data into the array
+  /**
+   Puts a uint16_t into the array. The data writen is network friendly.
+   @param d Data to write into the array
+   @param p Position to write data to. If left blank, will write to the  current caret position.
+   @param incpos Increments the caret position in the array. If set to false the function acts like a poke
+   @return The amount of bytes writen from the array
+   */
+  size_t put(const uint16_t d, const size_t p=N+1, const bool incpos=true)
+  {
+    if( p != N+1 ) 
+    {
+      data_array.rangecheck(p);
+      position(p);
+    }
+
+    *((uint16_t *)&data_array.elems[nap]) = htons(d);
+
+    if( incpos )
+    {
+      nap += sizeof(d);
+      if( nap > nal )
+        nal += sizeof(d);
+    }
+
+    return sizeof(d);
+  }
+
+  /// Gets data from the array
+  /**
+   Gets a uint32_t from the array. The data is host friendly.
+   @param d Data to retrieve
+   @param p Position to retrieve data from. If left blank, will retrieve from the current caret position
+   @param incpos Increments the caret position in the array. If set to false the function acts like a peek
+   @return The amount of bytes retrieved from the array
+   */
+  size_t get(uint32_t & d, const size_t p=N+1, const bool incpos=true)
+  {
+    if( p != N+1 ) 
+    {
+      data_array.rangecheck(p);
+      position(p);
+    }
+
+    d = ntohl( *((uint32_t *)&data_array.elems[nap]) );
+
+    if( incpos ) nap += sizeof(d);
+    return sizeof(d);
+  }
+
+  /// Puts data into the array
+  /**
+   Puts a uint32_t into the array. The data writen is network friendly.
+   @param d Data to write into the array
+   @param p Position to write data to. If left blank, will write to the current caret position.
+   @param incpos Increments the caret position in the array. If set to false the function acts like a poke
+   @return The amount of bytes writen from the array
+   */
+  size_t put(const uint32_t d, const size_t p=N+1, const bool incpos=true)
+  {
+    if( p != N+1 ) 
+    {
+      data_array.rangecheck(p);
+      position(p);
+    }
+
+    *((uint32_t *)&data_array.elems[nap]) = htonl(d);
+
+    if( incpos )
+    {
+      nap += sizeof(d);
+      if( nap > nal )
+        nal += sizeof(d);
+    }
+
+    return sizeof(d);
+  }
+
+  /// Gets data from the array
+  /**
+   Gets a uint32_t from the array. The data is host friendly.
+   @param d Data to retrieve
+   @param p Position to retrieve data from. If left blank, will retrieve from the current caret position
+   @param incpos Increments the caret position in the array. If set to false the function acts like a peek
+   @return The amount of bytes retrieved from the array
+   */
+  size_t get(ip::address_v4 & d, const size_t p=N+1, const bool incpos=true)
+  {
+    if( p != N+1 ) 
+    {
+      data_array.rangecheck(p);
+      position(p);
+    }
+
+    d = ip::address_v4( ntohl( *((uint32_t *)&data_array.elems[nap]) ) );
+
+    if( incpos ) nap += sizeof(uint32_t);
+    return sizeof(d);
+  }
+
+  /// Puts data into the array
+  /**
+   Puts a uint32_t into the array. The data writen is network friendly.
+   @param d Data to write into the array
+   @param p Position to write data to. If left blank, will write to the current caret position.
+   @param incpos Increments the caret position in the array. If set to false the function acts like a poke
+   @return The amount of bytes writen from the array
+   */
+  size_t put(const ip::address_v4 & d, const size_t p=N+1, const bool incpos=true)
+  {
+    if( p != N+1 ) 
+    {
+      data_array.rangecheck(p);
+      position(p);
+    }
+
+    *((uint32_t *)&data_array.elems[nap]) = htonl(
+            static_cast<uint32_t> (d.to_ulong())
+    );
+
+    if( incpos )
+    {
+      nap += sizeof(uint32_t);
+      if( nap > nal )
+        nal += sizeof(uint32_t);
+    }
+
+    return sizeof(d);
+  }
+
+  /// Gets data from the array
+  /**
+   Gets a uint32_t from the array. The data is host friendly.
+   @param d Data to retrieve
+   @param p Position to retrieve data from. If left blank, will retrieve from the current caret position
+   @param incpos Increments the caret position in the array. If set to false the function acts like a peek
+   @return The amount of bytes retrieved from the array
+   */
+  size_t get(ip::address_v6 & d, const size_t p=N+1, const bool incpos=true)
+  {
+    if( p != N+1 ) 
+    {
+      data_array.rangecheck(p);
+      position(p);
+    }
+
+    ip::address_v6::bytes_type  bytes;
+    memcpy( &bytes.elems[0], &data_array.elems[nap], 16);
+    d = ip::address_v6(bytes);
+    if( incpos )
+    {
+      nap += 16; 
+      if( nap > nal ) nal += 16;
+    }
+    return 16;
+  }
+
+  /// Puts data into the array
+  /**
+   Puts a uint32_t into the array. The data writen is network friendly.
+   @param d Data to write into the array
+   @param p Position to write data to. If left blank, will write to the current caret position.
+   @param incpos Increments the caret position in the array. If set to false the function acts like a poke
+   @return The amount of bytes writen from the array
+   */
+  size_t put(const ip::address_v6 & d, const size_t p=N+1, const bool incpos=true)
+  {
+    if( p != N+1 ) 
+    {
+      data_array.rangecheck(p);
+      position(p);
+    }
+
+    memcpy( &data_array.elems[nap], &d.to_bytes().elems[0], 16);
+
+    if( incpos )
+    {
+      nap += sizeof(uint32_t);
+      if( nap > nal )
+        nal += sizeof(uint32_t);
+    }
+
+    return sizeof(d);
+  }
+
+  /// Gets data from the array
+  /**
+   Gets a std::string from the array.
+   @param d Data to retrieve
+   @param len Amount of chars to read.
+   @param p Position to retrieve data from. If left blank, will retrieve from the current caret position
+   @param incpos Increments the caret position in the array. If set to false the function acts like a peek
+   @return The amount of bytes retrieved from the array
+   */
+  size_t get(string & d, const size_t len, const size_t p=N+1, const bool incpos=true)
+  {
+    if( p != N+1 ) 
+    {
+      data_array.rangecheck(p);
+      position(p);
+    }
+
+    scoped_array<char> cPtr( new char[len + 1] );
+    strncpy( cPtr.get(), (char*)&data_array.elems[nap], len);
+    cPtr.get()[len] = 0x00;
+    d = cPtr.get();
+
+    if( incpos )
+    {
+      nap += len;
+      if( nap > nal )
+        nal += len;
+    }
+
+    return len;
+  }
+
+  /// Puts data into the array
+  /**
+   Puts a std::string into the array.
+   @param d Data to write into the array
+   @param len Amount of chars to write
+   @param p Position to write data to. If left blank, will write to the current caret position.
+   @param incpos Increments the caret position in the array. If set to false the function acts like a poke
+   @return The amount of bytes writen from the array
+   */
+  size_t put(const string & d, const size_t len, const size_t p=N+1, const bool incpos=true)
+  {
+    if( p != N+1 ) 
+    {
+      data_array.rangecheck(p);
+      position(p);
+    }
+
+    // make sure we can memcpy!
+    data_array.rangecheck(nap + len);
+    memcpy( &data_array.elems[nap], d.c_str(), len );
+
+    if( incpos )
+    {
+      nap += len;
+      if( nap > nal )
+        nal += len;
+    }
+
+    return len;
+  }
+
+  /// Returns the underline boost::array to provide a compatible object.
+  /**
+   Returns the underline boost::array to provide a compatible object.
+   @return A boost::array compatible object
+   */
+  array<uint8_t, N>& get_array()
+  {
+    return data_array;
+  }
+
+};
+
+typedef network_array<576>        dns_buffer_t;
+typedef shared_ptr<dns_buffer_t>  shared_dns_buffer_t;
+
+
+  } // namespace net
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_NET_NETWORK_ARRAY_HPP
diff --git a/lib/boost-net-dns/boost/net/resolve.hpp b/lib/boost-net-dns/boost/net/resolve.hpp
new file mode 100755 (executable)
index 0000000..5ce0382
--- /dev/null
@@ -0,0 +1,232 @@
+//
+// resolve.hpp
+// ~~~~~~~~
+//
+// Copyright (c) 1998-2006 Andreas Haberstroh (andreas at ibusy dot com)
+//
+// 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_NET_DNS_RESOLVE_HPP
+#define BOOST_NET_DNS_RESOLVE_HPP
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/bind.hpp>
+#include <boost/thread/thread.hpp> 
+#include <boost/thread/condition.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/asio.hpp>
+#include <boost/net/dns.hpp>
+
+using namespace std;
+using namespace boost;
+using namespace boost::asio;
+
+namespace boost {
+  namespace net {
+    namespace dns {
+
+/// Provides DNS resolution using dns::message packets
+/**
+The resolve class makes a DNS resolution query synchronously.
+Internally, the class does the work asynchronously when multiple servers are listed.
+*/
+class resolve
+{
+private:
+
+  /*
+  need an atomic reference counter
+  */
+  class reference_counter\r
+  {\r
+  public:\r
+      reference_counter() : mutex(), count(0) { }\r
+      int inc()\r
+      {\r
+          boost::mutex::scoped_lock scoped_lock(mutex);\r
+          return ++count;\r
+      }\r
+      int dec()\r
+      {\r
+          boost::mutex::scoped_lock scoped_lock(mutex);\r
+          return --count;\r
+      }\r
+\r
+  private:\r
+      boost::mutex mutex;\r
+      mutable int count;\r
+  };\r
+
+private:
+  /// resolve has it's own io_service handler
+  io_service          ioservice;
+  ip::udp::socket     socket;
+
+  /// Timer used to retry sending a packet. Busy servers don't always anwers
+  deadline_timer      retry_timer;
+
+  /// Timer used to kill the async_dns_request if there isn't a response
+  deadline_timer      death_timer;
+
+  /// The maximum length async_dns_request should try to get a response.
+  uint32_t            death_timeout;
+    
+  /// List of servers to request resolution from
+  vector<ip::udp::endpoint> endpointList;
+  
+  /// Response message to pass back when a request is resolved
+  dns::message        responseMessage;
+
+  /// Outbound DNS request buffer 
+  dns_buffer_t  reqBuffer;
+
+  /// Number of servers left before 
+  reference_counter   requestCount;
+
+  /// General mutex for locking buffers
+  boost::mutex        bufferMutex;
+
+public:
+  /// Constructor for the resolve class
+  resolve()
+  : ioservice(), 
+    socket(ioservice, ip::udp::endpoint(ip::udp::v4(), 0)), 
+    retry_timer(ioservice), 
+    death_timer(ioservice), 
+    death_timeout(30),
+    endpointList(),
+    responseMessage(),
+    reqBuffer(),
+    requestCount(),
+    bufferMutex()
+  {
+  }
+
+  /// Adds a name server to the list of servers that we will query
+  /**
+  @param addr IP address for the name server
+  */
+  void addServer( ip::address & addr )
+  {
+    boost::mutex::scoped_lock lock(bufferMutex);
+    ip::udp::endpoint endpoint(addr, 53);
+    endpointList.push_back( endpoint );
+  }
+
+  /// Executes the DNS query
+  /**
+  @param qmessage Query message to send to the server list
+  @return Query result. If the query failed or timed out, dns::message.result() will return no_result.
+  */
+  dns::message & query(dns::message & qmessage)
+  {
+    // set a few defaults for a message
+    qmessage.recursive(true);
+    qmessage.action(dns::message::query);
+    qmessage.opcode(dns::message::squery);
+
+    // make our message id unique
+    qmessage.id( 0xaffe );
+      
+    qmessage.encode( reqBuffer );
+
+    // in the event nothing get's resolved, answer with the original question
+    responseMessage = qmessage;
+    responseMessage.result(dns::message::no_result);
+
+    // die if we don't get a response within death_timeout
+    death_timer.expires_from_now(boost::posix_time::seconds(death_timeout));
+    death_timer.async_wait(boost::bind(&resolve::request_timeout, this));
+
+    for( vector<ip::udp::endpoint>::iterator iter = endpointList.begin(); iter != endpointList.end(); ++iter )
+    {
+      // we're waiting for N of requests
+      requestCount.inc();
+
+      // setup the receive buffer
+      shared_dns_buffer_t recvBuffer( new dns_buffer_t );
+      socket.async_receive_from(
+          boost::asio::buffer( recvBuffer.get()->get_array() ), *iter,
+          boost::bind(&resolve::handle_recv, this, 
+            recvBuffer,
+            boost::asio::placeholders::error,
+            boost::asio::placeholders::bytes_transferred));
+    }
+
+    // kick off the request
+    send_packet();
+
+    // run a blocking service
+    ioservice.run();
+
+    return responseMessage;
+  }
+
+private:
+  void request_timeout()
+  {
+    retry_timer.cancel();
+    death_timer.cancel();
+
+    // just tear everything down at this point.
+    if( socket.is_open() )
+      socket.close();
+
+    if( requestCount.dec() == 0 )
+      ioservice.stop();
+  }
+
+  void resend_timeout()
+  {
+    retry_timer.cancel();
+
+    // No response, so resend the message again
+    if( socket.is_open() )
+      send_packet();
+    else
+      // if the socket gets closed, then, we've probably received an answer!
+      request_timeout();
+  }
+
+  void send_packet()
+  {
+    // 2 seconds should be a good time to wait for a response.
+    retry_timer.expires_from_now(boost::posix_time::seconds(2));
+    retry_timer.async_wait(boost::bind(&resolve::resend_timeout, this));
+
+    // send out the packets for request
+    for( vector<ip::udp::endpoint>::iterator iter = endpointList.begin(); iter != endpointList.end(); ++iter )
+      socket.send_to(boost::asio::buffer(reqBuffer.get_array()), *iter);
+  }
+
+  void handle_recv(shared_dns_buffer_t inBuffer, const boost::system::error_code& ec, std::size_t bytes_transferred)
+  {
+    if (!ec || ec == boost::asio::error::message_size)
+    {
+      // only decode if we haven't decoded already!
+      if( responseMessage.result() != dns::message::no_result )
+      {
+        boost::mutex::scoped_lock lock(bufferMutex);
+          
+        // clamp the recvBuffer with the number of bytes transferred
+        inBuffer.get()->length(bytes_transferred);
+
+        // decode the buffer and say we've succeeded
+        responseMessage.decode( *inBuffer.get() );
+      }
+
+      // consider the job done.
+      request_timeout();
+    }
+  }
+};
+
+      } // namespace dns
+  } // namespace net
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_NET_DNS_RESOLVE_HPP
diff --git a/lib/boost-net-dns/boost/net/rfc1035_414.hpp b/lib/boost-net-dns/boost/net/rfc1035_414.hpp
new file mode 100755 (executable)
index 0000000..1112854
--- /dev/null
@@ -0,0 +1,218 @@
+//
+// rfc1035_414.hpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 1998-2006 Andreas Haberstroh (andreas at ibusy dot com)
+//
+// 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_NET_RFC1035_414_HPP
+#define BOOST_NET_RFC1035_414_HPP
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <vector>
+#include <string>
+#include <map>
+
+#include <boost/tokenizer.hpp>\r
+#include <boost/algorithm/string/case_conv.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/net/network_array.hpp>
+
+
+using namespace std;
+using namespace boost;
+
+namespace boost {
+  namespace net {
+
+    typedef network_array<576> dns_buffer_t;
+
+    /*!
+      The rfc1035_414_t class is a helper class for dealing with DNS label compression inside
+      of DNS type packets. This class takes its name after RFC1035, section 4.1.4.
+    */
+    class rfc1035_414_t
+    {
+    private:
+      /*!
+      The domain_offset_map_t links buffer offsets to strings for the DNS label compression
+      requirements.
+      */
+      typedef std::map<string,size_t>   domain_offset_map_t;
+      
+      domain_offset_map_t _offsets;
+        
+    public:
+      /// Default constructor
+      rfc1035_414_t() : _offsets()
+      {
+      }
+
+      /// Copy constructor
+      rfc1035_414_t(const rfc1035_414_t& rfc)
+        : _offsets(rfc._offsets)
+      {
+      }
+
+      /// Assignment operator
+      rfc1035_414_t& operator=(const rfc1035_414_t& rfc)
+      {
+        _offsets = rfc._offsets;
+        return *this;
+      }
+
+      /*!
+      Breaks apart a domain name into it's label or compressed offset values and 
+      writes it to the buffer
+
+      \param domain Domain string to break apart into labels
+      \param buffer Memory buffer to write the labels to
+
+      \returns Number of bytes written
+      */
+      size_t write_label(const string& domain, dns_buffer_t & buffer)
+      {
+        // no length? no service
+        if( !domain.length() )
+          return 0;
+
+        string  lowerDomain = to_lower_copy(domain);
+        // total length of the data written.
+        size_t  length(0);
+
+        // place to begin the substring at
+        string::size_type begin(0);
+
+        bool  done = false;
+        while( !done )
+        {
+          // find the next '.' and cut the subdomain string from it.
+          string::size_type current = lowerDomain.find('.', begin);
+          string  subdomain( lowerDomain.substr(begin) );
+
+          // get the length of this label
+          uint8_t l( (uint8_t)(current - begin) );
+          if( current == string::npos )
+          {
+            l = (uint8_t)subdomain.length();
+            done = true;
+          }
+
+          // some how we've read a blank label!
+          if( !l ) break;
+
+          // current domain label
+          string  label( lowerDomain.substr(begin, l) );
+
+          // deja vous?
+          domain_offset_map_t::iterator iter = _offsets.find( subdomain );
+          if( iter == _offsets.end() )
+          {
+            // save the position in the buffer
+            _offsets[ subdomain ] = buffer.position();
+
+            buffer.put( (uint8_t)label.length() );
+            buffer.put( label, label.length() );
+            length += sizeof(uint8_t) + label.length();
+            begin = current + 1;
+          }
+          else
+          {
+            // compresses reference
+            size_t  offset = (0xC000 | iter->second);
+            buffer.put( (uint8_t)(offset >> 8) );
+            buffer.put( (uint8_t)(offset) );
+
+            // every byte counts
+            length += sizeof(uint16_t);
+            return length;
+          }
+        }
+
+        // need a zero termination to identify the "last" label
+        buffer.put( (uint8_t)0x00 );
+        length += sizeof(uint8_t);
+
+        return length;
+      }
+
+      /*!
+      Reads a sequence of labels from a memory buffer
+
+      This function is recursive in it's decompress. One of the things to be aware
+      of are DNS packets that make circular offset references. Also, malformed packets
+      that reference "bad" areas of the packet are no-no's
+
+      \param domain Domain label to return
+      \param buffer Memory buffer to read the domain from
+      \throws std::out_of_range
+      */
+      void read_label(string& domain, dns_buffer_t & buffer)
+      {
+        while( true )
+        {
+          uint8_t   len;
+          
+          size_t thisPos = buffer.position();
+          buffer.get(len);
+
+          // 0xC0 denotes the offset
+          if( len & 0xC0 )
+          {
+            uint8_t msb;
+            buffer.get(msb);
+            uint8_t lsb = len ^ 0xC0;
+            uint16_t offset = static_cast<uint16_t>(lsb << 8 | msb);
+            
+            // bad dog! trying to reference the header
+            if( offset < 0x0C )
+              throw std::out_of_range("Reference inside header"); // maybe we should throw a message?
+
+            // bad dog! trying to reference ourselves!
+            if( offset == thisPos )
+              throw std::out_of_range("Self Reference"); 
+
+            // bad dog! trying to reference out-of-bounds!
+            if( offset > buffer.length() )
+              throw std::out_of_range("Out of Bounds"); 
+
+            // recurse the reference !
+            size_t savedpos = buffer.position();
+
+            buffer.position(offset); // make the jump to the reference
+
+            read_label(domain, buffer);
+
+            // safe to restore!
+            if( savedpos < buffer.length() )
+              buffer.position(savedpos);
+
+            // the compressed reference has the ending 0x00 byte marker
+            break;
+          }
+          else if( len )
+          {
+            string s;
+            buffer.get( s, len );
+
+            domain += to_lower_copy(s) + ".";
+          }
+          else
+            break;
+        }
+
+        // we should always carry the "." in the name
+        if( !domain.length() ) domain = ".";
+      }
+    };
+
+  } // namespace net
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif  // BOOST_NET_RFC1035_414_HPP
index 079cfa7..be4b8e9 100644 (file)
@@ -1,3 +1,6 @@
+# package: find external packages
+include(FindPkgConfig)
+
 # package: required boost libraries
 set(Boost_USE_STATIC_LIBS ON)
 set(Boost_USE_MULTITHREADED ON)
@@ -6,8 +9,8 @@ find_package(Boost COMPONENTS filesystem program_options system REQUIRED)
 include_directories(${Boost_INCLUDE_DIRS})
 link_directories(${Boost_LIBRARY_DIRS})
 
-# package: find external packages
-include(FindPkgConfig)
+# package: boost-net-dns
+include_directories(${CMAKE_SOURCE_DIR}/lib/boost-net-dns)
 
 # package: libi2ncommon
 pkg_check_modules(I2NCOMMON REQUIRED libi2ncommon)
index 764ed95..4277ee3 100644 (file)
@@ -3,12 +3,17 @@
 #include <iostream>
 
 #include <boost/asio.hpp>
+#include <boost/net/dns.hpp>
+#include <boost/net/resolve.hpp>
 
 #include "dns/hostaddress.h"
 
 using namespace std;
 using boost::asio::io_service;
-using boost::asio::ip::tcp;
+using boost::asio::ip::address;
+using boost::net::dns::a_resource;
+using boost::net::dns::message;
+using boost::net::dns::rr_list_t;
 
 //-----------------------------------------------------------------------------
 // DnsResolver
@@ -37,22 +42,38 @@ bool DnsResolver::resolve()
 
     try
     {
-        io_service io_serv;
-        tcp::resolver resolver( io_serv );
-        tcp::resolver::query query( tcp::v4(), HostDnsAddress, "" );
-        tcp::resolver::iterator it_first = resolver.resolve( query );
-        tcp::resolver::iterator it_last = tcp::resolver::iterator();
-        while ( it_first != it_last )
+        address nameServer( address::from_string( "127.0.0.1" ) );
+        boost::net::dns::resolve resolver;
+        resolver.addServer( nameServer );
+        message dns_message( HostDnsAddress, boost::net::dns::type_a );
+        message& dns_packet = resolver.query( dns_message );
+        rr_list_t* answers = dns_packet.answers();
+        int resolved_ip = answers->size();
+        if ( resolved_ip < 1 )
         {
-            string dest_ip = (*it_first).endpoint().address().to_string();
+            cerr << "Error: host " << HostDnsAddress << " could not be resolved." << endl;
+            return false;
+        }
+
+        for ( rr_list_t::iterator riter = answers->begin();
+              riter != answers->end();
+              ++riter )
+        {
+            a_resource *resource_record = dynamic_cast<a_resource*> (
+                    riter->get()
+            );
 
-            HostAddress resolved_host;
-            resolved_host.set_ip( dest_ip );
-            ResolvedHostAddressList.push_back( resolved_host );
+            if ( ( resource_record != NULL ) &&
+                 ( resource_record->rtype() == boost::net::dns::type_a ) )
+            {
+                string ip = resource_record->address().to_string();
+                int ttl = resource_record->ttl();
 
-            cout << "- " << dest_ip << endl;
+                HostAddress resolved_host( ip, ttl );
+                ResolvedHostAddressList.push_back( resolved_host );
 
-            ++it_first;
+                cout << "- " << ip << endl;
+            }
         }
     }
     catch ( const std::exception &ex )
@@ -96,5 +117,7 @@ string DnsResolver::get_next_ip()
 
     BOOST_ASSERT( list_size_before == list_size_after );
 
+    // TODO check the ttl of the resolved IP, if it is next to zero, call the resolve again
+
     return destination_ip;
 }
index 46a60ca..a7cc69c 100644 (file)
@@ -12,6 +12,15 @@ HostAddress::HostAddress() :
 {
 }
 
+HostAddress::HostAddress(
+        string ip,
+        int ttl
+) :
+    Ip( ip ),
+    Ttl( ttl )
+{
+}
+
 HostAddress::~HostAddress()
 {
 }
index 525761b..1185fa1 100644 (file)
@@ -13,6 +13,7 @@ class HostAddress
 {
 public:
     HostAddress();
+    HostAddress( std::string ip, int ttl );
     virtual ~HostAddress();
 
     std::string get_ip() const;