udpdns.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. // Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. // $Id$
  15. #ifndef __UDPDNS_H
  16. #define __UDPDNS_H 1
  17. #include <config.h>
  18. #include <asio.hpp>
  19. #include <boost/shared_array.hpp>
  20. #include <boost/shared_ptr.hpp>
  21. #include <dns/buffer.h>
  22. #include <dns/message.h>
  23. #include <dns/messagerenderer.h>
  24. #include <asiolink/asiolink.h>
  25. #include <asiolink/internal/coroutine.h>
  26. // This file contains UDP-specific implementations of generic classes
  27. // defined in asiolink.h. It is *not* intended to be part of the public
  28. // API.
  29. namespace asiolink {
  30. /// \brief The \c UDPEndpoint class is a concrete derived class of
  31. /// \c IOEndpoint that represents an endpoint of a UDP packet.
  32. ///
  33. /// Other notes about \c TCPEndpoint applies to this class, too.
  34. class UDPEndpoint : public IOEndpoint {
  35. public:
  36. ///
  37. /// \name Constructors and Destructor.
  38. ///
  39. //@{
  40. /// \brief Constructor from a pair of address and port.
  41. ///
  42. /// \param address The IP address of the endpoint.
  43. /// \param port The UDP port number of the endpoint.
  44. UDPEndpoint(const IOAddress& address, const unsigned short port) :
  45. asio_endpoint_placeholder_(
  46. new asio::ip::udp::endpoint(asio::ip::address::from_string(address.toText()),
  47. port)),
  48. asio_endpoint_(*asio_endpoint_placeholder_)
  49. {}
  50. /// \brief Constructor from an ASIO UDP endpoint.
  51. ///
  52. /// This constructor is designed to be an efficient wrapper for the
  53. /// corresponding ASIO class, \c udp::endpoint.
  54. ///
  55. /// \param asio_endpoint The ASIO representation of the UDP endpoint.
  56. UDPEndpoint(const asio::ip::udp::endpoint& asio_endpoint) :
  57. asio_endpoint_placeholder_(NULL), asio_endpoint_(asio_endpoint)
  58. {}
  59. /// \brief The destructor.
  60. ~UDPEndpoint() { delete asio_endpoint_placeholder_; }
  61. //@}
  62. inline IOAddress getAddress() const {
  63. return (asio_endpoint_.address());
  64. }
  65. inline uint16_t getPort() const {
  66. return (asio_endpoint_.port());
  67. }
  68. inline short getProtocol() const {
  69. return (asio_endpoint_.protocol().protocol());
  70. }
  71. inline short getFamily() const {
  72. return (asio_endpoint_.protocol().family());
  73. }
  74. // This is not part of the exosed IOEndpoint API but allows
  75. // direct access to the ASIO implementation of the endpoint
  76. inline const asio::ip::udp::endpoint& getASIOEndpoint() const {
  77. return (asio_endpoint_);
  78. }
  79. private:
  80. const asio::ip::udp::endpoint* asio_endpoint_placeholder_;
  81. const asio::ip::udp::endpoint& asio_endpoint_;
  82. };
  83. /// \brief The \c UDPSocket class is a concrete derived class of
  84. /// \c IOSocket that represents a UDP socket.
  85. ///
  86. /// Other notes about \c TCPSocket applies to this class, too.
  87. class UDPSocket : public IOSocket {
  88. private:
  89. UDPSocket(const UDPSocket& source);
  90. UDPSocket& operator=(const UDPSocket& source);
  91. public:
  92. /// \brief Constructor from an ASIO UDP socket.
  93. ///
  94. /// \param socket The ASIO representation of the UDP socket.
  95. UDPSocket(asio::ip::udp::socket& socket) : socket_(socket) {}
  96. virtual int getNative() const { return (socket_.native()); }
  97. virtual int getProtocol() const { return (IPPROTO_UDP); }
  98. private:
  99. asio::ip::udp::socket& socket_;
  100. };
  101. //
  102. // Asynchronous UDP server coroutine
  103. //
  104. ///
  105. /// \brief This class implements the coroutine to handle UDP
  106. /// DNS query event. As such, it is both a \c DNSServer and
  107. /// a \c coroutine
  108. ///
  109. class UDPServer : public virtual DNSServer, public virtual coroutine {
  110. public:
  111. /// \brief Constructor
  112. /// \param io_service the asio::io_service to work with
  113. /// \param addr the IP address to listen for queries on
  114. /// \param port the port to listen for queries on
  115. /// \param checkin the callbackprovider for non-DNS events
  116. /// \param lookup the callbackprovider for DNS lookup events
  117. /// \param answer the callbackprovider for DNS answer events
  118. explicit UDPServer(asio::io_service& io_service,
  119. const asio::ip::address& addr, const uint16_t port,
  120. SimpleCallback* checkin = NULL,
  121. DNSLookup* lookup = NULL,
  122. DNSAnswer* answer = NULL);
  123. /// \brief The function operator
  124. void operator()(asio::error_code ec = asio::error_code(),
  125. size_t length = 0);
  126. /// \brief Calls the lookup callback
  127. void asyncLookup();
  128. /// \brief Resume operation
  129. ///
  130. /// \param done Set this to true if the lookup action is done and
  131. /// we have an answer
  132. void resume(const bool done);
  133. /// \brief Check if we have an answer
  134. ///
  135. /// \return true if we have an answer
  136. bool hasAnswer() { return (done_); }
  137. /// \brief Returns the coroutine state value
  138. ///
  139. /// \return the coroutine state value
  140. int value() { return (get_value()); }
  141. /// \brief Clones the object
  142. ///
  143. /// \return a newly allocated copy of this object
  144. DNSServer* clone() {
  145. UDPServer* s = new UDPServer(*this);
  146. return (s);
  147. }
  148. private:
  149. enum { MAX_LENGTH = 4096 };
  150. // The ASIO service object
  151. asio::io_service& io_;
  152. // Class member variables which are dynamic, and changes to which
  153. // need to accessible from both sides of a coroutine fork or from
  154. // outside of the coroutine (i.e., from an asynchronous I/O call),
  155. // should be declared here as pointers and allocated in the
  156. // constructor or in the coroutine. This allows state information
  157. // to persist when an individual copy of the coroutine falls out
  158. // scope while waiting for an event, *so long as* there is another
  159. // object that is referencing the same data. As a side-benefit, using
  160. // pointers also reduces copy overhead for coroutine objects.
  161. //
  162. // Note: Currently these objects are allocated by "new" in the
  163. // constructor, or in the function operator while processing a query.
  164. // Repeated allocations from the heap for every incoming query is
  165. // clearly a performance issue; this must be optimized in the future.
  166. // The plan is to have a structure pre-allocate several "server state"
  167. // objects which can be pulled off a free list and placed on an in-use
  168. // list whenever a query comes in. This will serve the dual purpose
  169. // of improving performance and guaranteeing that state information
  170. // will *not* be destroyed when any one instance of the coroutine
  171. // falls out of scope while waiting for an event.
  172. //
  173. // Socket used to for listen for queries. Created in the
  174. // constructor and stored in a shared_ptr because socket objects
  175. // are not copyable.
  176. boost::shared_ptr<asio::ip::udp::socket> socket_;
  177. // The ASIO-enternal endpoint object representing the client
  178. boost::shared_ptr<asio::ip::udp::endpoint> sender_;
  179. // \c IOMessage and \c Message objects to be passed to the
  180. // DNS lookup and answer providers
  181. boost::shared_ptr<asiolink::IOMessage> io_message_;
  182. isc::dns::MessagePtr message_;
  183. // The buffer into which the response is written
  184. isc::dns::OutputBufferPtr respbuf_;
  185. // The buffer into which the query packet is written
  186. boost::shared_array<char> data_;
  187. // State information that is entirely internal to a given instance
  188. // of the coroutine can be declared here.
  189. size_t bytes_;
  190. bool done_;
  191. // Callback functions provided by the caller
  192. const SimpleCallback* checkin_callback_;
  193. const DNSLookup* lookup_callback_;
  194. const DNSAnswer* answer_callback_;
  195. boost::shared_ptr<IOEndpoint> peer_;
  196. boost::shared_ptr<IOSocket> iosock_;
  197. };
  198. //
  199. // Asynchronous UDP coroutine for upstream queries
  200. //
  201. class UDPQuery : public coroutine {
  202. public:
  203. // TODO Maybe this should be more generic than just for UDPQuery?
  204. ///
  205. /// \brief Result of the query
  206. ///
  207. /// This is related only to contacting the remote server. If the answer
  208. ///indicates error, it is still counted as SUCCESS here, if it comes back.
  209. ///
  210. enum Result {
  211. SUCCESS,
  212. TIME_OUT,
  213. STOPPED
  214. };
  215. /// Abstract callback for the UDPQuery.
  216. class Callback {
  217. public:
  218. virtual ~Callback() {}
  219. /// This will be called when the UDPQuery is completed
  220. virtual void operator()(Result result) = 0;
  221. };
  222. ///
  223. /// \brief Constructor.
  224. ///
  225. /// It creates the query.
  226. /// @param callback will be called when we terminate. It is your task to
  227. /// delete it if allocated on heap.
  228. ///@param timeout in ms.
  229. ///
  230. explicit UDPQuery(asio::io_service& io_service,
  231. const isc::dns::Question& q,
  232. const IOAddress& addr, uint16_t port,
  233. isc::dns::OutputBufferPtr buffer,
  234. Callback* callback, int timeout = -1);
  235. void operator()(asio::error_code ec = asio::error_code(),
  236. size_t length = 0);
  237. /// Terminate the query.
  238. void stop(Result reason = STOPPED);
  239. private:
  240. enum { MAX_LENGTH = 4096 };
  241. ///
  242. /// \short Private data
  243. ///
  244. /// They are not private because of stability of the
  245. /// interface (this is private class anyway), but because this class
  246. /// will be copyed often (it is used as a coroutine and passed as callback
  247. /// to many async_*() functions) and we want keep the same data. Some of
  248. /// the data is not copyable too.
  249. ///
  250. struct PrivateData;
  251. boost::shared_ptr<PrivateData> data_;
  252. };
  253. }
  254. #endif // __UDPDNS_H
  255. // Local Variables:
  256. // mode: c++
  257. // End: