asiolink.h 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  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 __ASIOLINK_H
  16. #define __ASIOLINK_H 1
  17. // IMPORTANT NOTE: only very few ASIO headers files can be included in
  18. // this file. In particular, asio.hpp should never be included here.
  19. // See the description of the namespace below.
  20. #include <unistd.h> // for some network system calls
  21. #include <asio/ip/address.hpp>
  22. #include <functional>
  23. #include <string>
  24. #include <dns/buffer.h>
  25. #include <dns/message.h>
  26. #include <dns/question.h>
  27. #include <exceptions/exceptions.h>
  28. #include <asiolink/ioaddress.h>
  29. #include <asiolink/ioendpoint.h>
  30. #include <asiolink/iomessage.h>
  31. #include <asiolink/iosocket.h>
  32. //#include <asio/io_service.hpp>
  33. namespace asio {
  34. // forward declaration for IOService::get_io_service() below
  35. class DNSService;
  36. class io_service;
  37. }
  38. /// \namespace asiolink
  39. /// \brief A wrapper interface for the ASIO library.
  40. ///
  41. /// The \c asiolink namespace is used to define a set of wrapper interfaces
  42. /// for the ASIO library.
  43. ///
  44. /// BIND 10 uses the non-Boost version of ASIO because it's header-only,
  45. /// i.e., does not require a separate library object to be linked, and thus
  46. /// lowers the bar for introduction.
  47. ///
  48. /// But the advantage comes with its own costs: since the header-only version
  49. /// includes more definitions in public header files, it tends to trigger
  50. /// more compiler warnings for our own sources, and, depending on the
  51. /// compiler options, may make the build fail.
  52. ///
  53. /// We also found it may be tricky to use ASIO and standard C++ libraries
  54. /// in a single translation unit, i.e., a .cc file: depending on the order
  55. /// of including header files, ASIO may or may not work on some platforms.
  56. ///
  57. /// This wrapper interface is intended to centralize these
  58. /// problematic issues in a single sub module. Other BIND 10 modules should
  59. /// simply include \c asiolink.h and use the wrapper API instead of
  60. /// including ASIO header files and using ASIO-specific classes directly.
  61. ///
  62. /// This wrapper may be used for other IO libraries if and when we want to
  63. /// switch, but generality for that purpose is not the primary goal of
  64. /// this module. The resulting interfaces are thus straightforward mapping
  65. /// to the ASIO counterparts.
  66. ///
  67. /// Notes to developers:
  68. /// Currently the wrapper interface is fairly specific to use by a
  69. /// DNS server, i.e., b10-auth or b10-recurse. But the plan is to
  70. /// generalize it and have other modules use it as well.
  71. ///
  72. /// One obvious drawback of this approach is performance overhead
  73. /// due to the additional layer. We should eventually evaluate the cost
  74. /// of the wrapper abstraction in benchmark tests. Another drawback is
  75. /// that the wrapper interfaces don't provide all features of ASIO
  76. /// (at least for the moment). We should also re-evaluate the
  77. /// maintenance overhead of providing necessary wrappers as we develop
  78. /// more.
  79. ///
  80. /// On the other hand, we may be able to exploit the wrapper approach to
  81. /// simplify the interfaces (by limiting the usage) and unify performance
  82. /// optimization points.
  83. ///
  84. /// As for optimization, we may want to provide a custom allocator for
  85. /// the placeholder of callback handlers:
  86. /// http://think-async.com/Asio/asio-1.3.1/doc/asio/reference/asio_handler_allocate.html
  87. namespace asiolink {
  88. struct DNSServiceImpl;
  89. struct IOServiceImpl;
  90. /// \brief An exception that is thrown if an error occurs within the IO
  91. /// module. This is mainly intended to be a wrapper exception class for
  92. /// ASIO specific exceptions.
  93. class IOError : public isc::Exception {
  94. public:
  95. IOError(const char* file, size_t line, const char* what) :
  96. isc::Exception(file, line, what) {}
  97. };
  98. /// \brief Forward declarations for classes used below
  99. class SimpleCallback;
  100. class DNSLookup;
  101. class DNSAnswer;
  102. /// \brief The \c IOService class is a wrapper for the ASIO \c io_service
  103. /// class.
  104. ///
  105. /// Currently, the interface of this class is very specific to the
  106. /// authoritative/recursive DNS server implementationss in b10-auth
  107. /// and b10-recurse; this is reflected in the constructor signatures.
  108. /// Ultimately the plan is to generalize it so that other BIND 10
  109. /// modules can use this interface, too.
  110. class IOService {
  111. ///
  112. /// \name Constructors and Destructor
  113. ///
  114. /// These are currently very specific to the authoritative server
  115. /// implementation.
  116. ///
  117. /// Note: The copy constructor and the assignment operator are
  118. /// intentionally defined as private, making this class non-copyable.
  119. //@{
  120. private:
  121. IOService(const IOService& source);
  122. IOService& operator=(const IOService& source);
  123. public:
  124. /// \brief The constructor
  125. IOService();
  126. /// \brief The destructor.
  127. ~IOService();
  128. //@}
  129. /// \brief Start the underlying event loop.
  130. ///
  131. /// This method does not return control to the caller until
  132. /// the \c stop() method is called via some handler.
  133. void run();
  134. /// \brief Run the underlying event loop for a single event.
  135. ///
  136. /// This method return control to the caller as soon as the
  137. /// first handler has completed. (If no handlers are ready when
  138. /// it is run, it will block until one is.)
  139. void run_one();
  140. /// \brief Stop the underlying event loop.
  141. ///
  142. /// This will return the control to the caller of the \c run() method.
  143. void stop();
  144. /// \brief Return the native \c io_service object used in this wrapper.
  145. ///
  146. /// This is a short term work around to support other BIND 10 modules
  147. /// that share the same \c io_service with the authoritative server.
  148. /// It will eventually be removed once the wrapper interface is
  149. /// generalized.
  150. asio::io_service& get_io_service();
  151. private:
  152. IOServiceImpl* io_impl_;
  153. };
  154. class DNSService {
  155. ///
  156. /// \name Constructors and Destructor
  157. ///
  158. /// These are currently very specific to the authoritative server
  159. /// implementation.
  160. ///
  161. /// Note: The copy constructor and the assignment operator are
  162. /// intentionally defined as private, making this class non-copyable.
  163. //@{
  164. private:
  165. DNSService(const DNSService& source);
  166. DNSService& operator=(const DNSService& source);
  167. public:
  168. /// \brief The constructor with a specific IP address and port on which
  169. /// the services listen on.
  170. DNSService(IOService& io_service, const char& port, const char& address,
  171. SimpleCallback* checkin,
  172. DNSLookup* lookup,
  173. DNSAnswer* answer);
  174. /// \brief The constructor with a specific port on which the services
  175. /// listen on.
  176. ///
  177. /// It effectively listens on "any" IPv4 and/or IPv6 addresses.
  178. /// IPv4/IPv6 services will be available if and only if \c use_ipv4
  179. /// or \c use_ipv6 is \c true, respectively.
  180. DNSService(IOService& io_service, const char& port, const bool use_ipv4, const bool use_ipv6,
  181. SimpleCallback* checkin,
  182. DNSLookup* lookup,
  183. DNSAnswer* answer);
  184. /// \brief The destructor.
  185. ~DNSService();
  186. //@}
  187. /// \brief Start the underlying event loop.
  188. ///
  189. /// This method does not return control to the caller until
  190. /// the \c stop() method is called via some handler.
  191. // void run();
  192. /// \brief Run the underlying event loop for a single event.
  193. ///
  194. /// This method return control to the caller as soon as the
  195. /// first handler has completed. (If no handlers are ready when
  196. /// it is run, it will block until one is.)
  197. // void run_one();
  198. /// \brief Stop the underlying event loop.
  199. ///
  200. /// This will return the control to the caller of the \c run() method.
  201. // void stop();
  202. /// \brief Return the native \c io_service object used in this wrapper.
  203. ///
  204. /// This is a short term work around to support other BIND 10 modules
  205. /// that share the same \c io_service with the authoritative server.
  206. /// It will eventually be removed once the wrapper interface is
  207. /// generalized.
  208. asio::io_service& get_io_service() { return io_service_.get_io_service(); };
  209. private:
  210. DNSServiceImpl* impl_;
  211. IOService& io_service_;
  212. };
  213. /// \brief The \c DNSServer class is a wrapper (and base class) for
  214. /// classes which provide DNS server functionality.
  215. ///
  216. /// The classes derived from this one, \c TCPServer and \c UDPServer,
  217. /// act as the interface layer between clients sending queries, and
  218. /// functions defined elsewhere that provide answers to those queries.
  219. /// Those functions are described in more detail below under
  220. /// \c SimpleCallback, \c DNSLookup, and \c DNSAnswer.
  221. ///
  222. /// Notes to developers:
  223. /// When constructed, this class (and its derived classes) will have its
  224. /// "self_" member set to point to "this". Calls to methods in the base
  225. /// class are then rerouted via this pointer to methods in the derived
  226. /// class. This allows code from outside asiolink, with no specific
  227. /// knowledge of \c TCPServer or \c UDPServer, to access their methods.
  228. ///
  229. /// This class is both assignable and copy-constructable. Its subclasses
  230. /// use the "stackless coroutine" pattern, meaning that it will copy itself
  231. /// when "forking", and that instances will be posted as ASIO handler
  232. /// objects, which are always copied.
  233. ///
  234. /// Because these objects are frequently copied, it is recommended
  235. /// that derived classes be kept small to reduce copy overhead.
  236. class DNSServer {
  237. protected:
  238. ///
  239. /// \name Constructors and destructors
  240. ///
  241. /// This is intentionally defined as \c protected, as this base class
  242. /// should never be instantiated except as part of a derived class.
  243. //@{
  244. DNSServer() : self_(this) {}
  245. public:
  246. /// \brief The destructor
  247. virtual ~DNSServer() {}
  248. //@}
  249. ///
  250. /// \name Class methods
  251. ///
  252. /// These methods all make their calls indirectly via the "self_"
  253. /// pointer, ensuring that the functions ultimately invoked will be
  254. /// the ones in the derived class. This makes it possible to pass
  255. /// instances of derived classes as references to this base class
  256. /// without losing access to derived class data.
  257. ///
  258. //@{
  259. /// \brief The funtion operator
  260. virtual void operator()(asio::error_code ec = asio::error_code(),
  261. size_t length = 0)
  262. {
  263. (*self_)(ec, length);
  264. }
  265. /// \brief Resume processing of the server coroutine after an
  266. /// asynchronous call (e.g., to the DNS Lookup provider) has completed.
  267. virtual inline void resume(const bool done) { self_->resume(done); }
  268. /// \brief Indicate whether the server is able to send an answer
  269. /// to a query.
  270. ///
  271. /// This is presently used only for testing purposes.
  272. virtual inline bool hasAnswer() { return (self_->hasAnswer()); }
  273. /// \brief Returns the current value of the 'coroutine' object
  274. ///
  275. /// This is a temporary method, intended to be used for debugging
  276. /// purposes during development and removed later. It allows
  277. /// callers from outside the coroutine object to retrieve information
  278. /// about its current state.
  279. virtual inline int value() { return (self_->value()); }
  280. /// \brief Returns a pointer to a clone of this DNSServer object.
  281. ///
  282. /// When a \c DNSServer object is copied or assigned, the result will
  283. /// normally be another \c DNSServer object containing a copy
  284. /// of the original "self_" pointer. Calling clone() guarantees
  285. /// that the underlying object is also correctly copied.
  286. virtual inline DNSServer* clone() { return (self_->clone()); }
  287. //@}
  288. protected:
  289. /// \brief Lookup handler object.
  290. ///
  291. /// This is a protected class; it can only be instantiated
  292. /// from within a derived class of \c DNSServer.
  293. ///
  294. /// A server object that has received a query creates an instance
  295. /// of this class and scheudles it on the ASIO service queue
  296. /// using asio::io_service::post(). When the handler executes, it
  297. /// calls the asyncLookup() method in the server object to start a
  298. /// DNS lookup. When the lookup is complete, the server object is
  299. /// scheduled to resume, again using io_service::post().
  300. ///
  301. /// Note that the calling object is copied into the handler object,
  302. /// not referenced. This is because, once the calling object yields
  303. /// control to the handler, it falls out of scope and may disappear
  304. template <typename T>
  305. class AsyncLookup {
  306. public:
  307. AsyncLookup(T caller) : caller_(caller) {}
  308. inline void operator()() { caller_.asyncLookup(); }
  309. private:
  310. T caller_;
  311. };
  312. /// \brief Carries out a DNS lookup.
  313. ///
  314. /// This function calls the \c DNSLookup object specified by the
  315. /// DNS server when the \c IOService was created, passing along
  316. /// the details of the query and a pointer back to the current
  317. /// server object. It is called asynchronously via the AsyncLookup
  318. /// handler class.
  319. virtual inline void asyncLookup() { self_->asyncLookup(); }
  320. private:
  321. DNSServer* self_;
  322. };
  323. /// \brief The \c DNSLookup class is an abstract base class for a DNS
  324. /// Lookup provider function.
  325. ///
  326. /// Specific derived class implementations are hidden within the
  327. /// implementation. Instances of the derived classes can be called
  328. /// as functions via the operator() interface. Pointers to these
  329. /// instances can then be provided to the \c IOService class
  330. /// via its constructor.
  331. ///
  332. /// A DNS Lookup provider function obtains the data needed to answer
  333. /// a DNS query (e.g., from authoritative data source, cache, or upstream
  334. /// query). After it has run, the OutputBuffer object passed to it
  335. /// should contain the answer to the query, in an internal representation.
  336. class DNSLookup {
  337. ///
  338. /// \name Constructors and Destructor
  339. ///
  340. /// Note: The copy constructor and the assignment operator are
  341. /// intentionally defined as private, making this class non-copyable.
  342. //@{
  343. private:
  344. DNSLookup(const DNSLookup& source);
  345. DNSLookup& operator=(const DNSLookup& source);
  346. protected:
  347. /// \brief The default constructor.
  348. ///
  349. /// This is intentionally defined as \c protected as this base class
  350. /// should never be instantiated (except as part of a derived class).
  351. DNSLookup() : self_(this) {}
  352. public:
  353. /// \brief The destructor
  354. virtual ~DNSLookup() {}
  355. //@}
  356. /// \brief The function operator
  357. ///
  358. /// This makes its call indirectly via the "self" pointer, ensuring
  359. /// that the function ultimately invoked will be the one in the derived
  360. /// class.
  361. virtual void operator()(const IOMessage& io_message,
  362. isc::dns::MessagePtr message,
  363. isc::dns::OutputBufferPtr buffer,
  364. DNSServer* server) const
  365. {
  366. (*self_)(io_message, message, buffer, server);
  367. }
  368. private:
  369. DNSLookup* self_;
  370. };
  371. /// \brief The \c DNSAnswer class is an abstract base class for a DNS
  372. /// Answer provider function.
  373. ///
  374. /// Specific derived class implementations are hidden within the
  375. /// implementation. Instances of the derived classes can be called
  376. /// as functions via the operator() interface. Pointers to these
  377. /// instances can then be provided to the \c IOService class
  378. /// via its constructor.
  379. ///
  380. /// A DNS Answer provider function takes answer data that has been obtained
  381. /// from a DNS Lookup provider functon and readies it to be sent to the
  382. /// client. After it has run, the OutputBuffer object passed to it should
  383. /// contain the answer to the query rendered into wire format.
  384. class DNSAnswer {
  385. ///
  386. /// \name Constructors and Destructor
  387. ///
  388. /// Note: The copy constructor and the assignment operator are
  389. /// intentionally defined as private, making this class non-copyable.
  390. //@{
  391. private:
  392. DNSAnswer(const DNSAnswer& source);
  393. DNSAnswer& operator=(const DNSAnswer& source);
  394. protected:
  395. /// \brief The default constructor.
  396. ///
  397. /// This is intentionally defined as \c protected as this base class
  398. /// should never be instantiated (except as part of a derived class).
  399. DNSAnswer() {}
  400. public:
  401. /// \brief The destructor
  402. virtual ~DNSAnswer() {}
  403. //@}
  404. /// \brief The function operator
  405. virtual void operator()(const IOMessage& io_message,
  406. isc::dns::MessagePtr message,
  407. isc::dns::OutputBufferPtr buffer) const = 0;
  408. };
  409. /// \brief The \c SimpleCallback class is an abstract base class for a
  410. /// simple callback function with the signature:
  411. ///
  412. /// Specific derived class implementations are hidden within the
  413. /// implementation. Instances of the derived classes can be called
  414. /// as functions via the operator() interface. Pointers to these
  415. /// instances can then be provided to the \c IOService class
  416. /// via its constructor.
  417. ///
  418. /// The \c SimpleCallback is expected to be used for basic, generic
  419. /// tasks such as checking for configuration changes. It may also be
  420. /// used for testing purposes.
  421. class SimpleCallback {
  422. ///
  423. /// \name Constructors and Destructor
  424. ///
  425. /// Note: The copy constructor and the assignment operator are
  426. /// intentionally defined as private, making this class non-copyable.
  427. //@{
  428. private:
  429. SimpleCallback(const SimpleCallback& source);
  430. SimpleCallback& operator=(const SimpleCallback& source);
  431. protected:
  432. /// \brief The default constructor.
  433. ///
  434. /// This is intentionally defined as \c protected as this base class
  435. /// should never be instantiated (except as part of a derived class).
  436. SimpleCallback() : self_(this) {}
  437. public:
  438. /// \brief The destructor
  439. virtual ~SimpleCallback() {}
  440. /// \brief The function operator
  441. //@}
  442. ///
  443. /// This makes its call indirectly via the "self" pointer, ensuring
  444. /// that the function ultimately invoked will be the one in the derived
  445. /// class.
  446. virtual void operator()(const IOMessage& io_message) const {
  447. (*self_)(io_message);
  448. }
  449. private:
  450. SimpleCallback* self_;
  451. };
  452. /// \brief The \c RecursiveQuery class provides a layer of abstraction around
  453. /// the ASIO code that carries out an upstream query.
  454. ///
  455. /// This design is very preliminary; currently it is only capable of
  456. /// handling simple forward requests to a single resolver.
  457. class RecursiveQuery {
  458. ///
  459. /// \name Constructors
  460. ///
  461. //@{
  462. public:
  463. /// \brief Constructor for use when acting as a forwarder
  464. ///
  465. /// This is currently the only way to construct \c RecursiveQuery
  466. /// object. The address of the forward nameserver is specified,
  467. /// and all upstream queries will be sent to that one address.
  468. RecursiveQuery(DNSService& dns_service, const char& forward,
  469. uint16_t port = 53);
  470. //@}
  471. /// \brief Initiates an upstream query in the \c RecursiveQuery object.
  472. ///
  473. /// \param question The question being answered <qname/qclass/qtype>
  474. /// \param buffer An output buffer into which the response can be copied
  475. /// \param server A pointer to the \c DNSServer object handling the client
  476. ///
  477. /// When sendQuery() is called, a message is sent asynchronously to
  478. /// the upstream name server. When a reply arrives, 'server'
  479. /// is placed on the ASIO service queue via io_service::post(), so
  480. /// that the original \c DNSServer objct can resume processing.
  481. void sendQuery(const isc::dns::Question& question,
  482. isc::dns::OutputBufferPtr buffer,
  483. DNSServer* server);
  484. private:
  485. DNSService& dns_service_;
  486. IOAddress ns_addr_;
  487. uint16_t port_;
  488. };
  489. } // asiolink
  490. #endif // __ASIOLINK_H
  491. // Local Variables:
  492. // mode: c++
  493. // End: