# uml cache files
*.vpp~*
+
+# version control (CVS, SVN, GIT)
+.cvs
+.svn
--- /dev/null
+//
+// 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
--- /dev/null
+//
+// 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
--- /dev/null
+//
+// 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
--- /dev/null
+//
+// 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
--- /dev/null
+//
+// 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
--- /dev/null
+//
+// 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
--- /dev/null
+//
+// 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
--- /dev/null
+//
+// 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
--- /dev/null
+//
+// 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
--- /dev/null
+//
+// 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
+# package: find external packages
+include(FindPkgConfig)
+
# package: required boost libraries
set(Boost_USE_STATIC_LIBS ON)
set(Boost_USE_MULTITHREADED ON)
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)
#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
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 )
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;
}
{
}
+HostAddress::HostAddress(
+ string ip,
+ int ttl
+) :
+ Ip( ip ),
+ Ttl( ttl )
+{
+}
+
HostAddress::~HostAddress()
{
}
{
public:
HostAddress();
+ HostAddress( std::string ip, int ttl );
virtual ~HostAddress();
std::string get_ip() const;