asiolink.cc 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  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. #include <config.h>
  16. #include <unistd.h> // for some IPC/network system calls
  17. #include <sys/socket.h>
  18. #include <netinet/in.h>
  19. #include <asio.hpp>
  20. #include <boost/lexical_cast.hpp>
  21. #include <boost/bind.hpp>
  22. #include <boost/shared_ptr.hpp>
  23. #include <dns/buffer.h>
  24. #include <dns/message.h>
  25. #include <asiolink/asiolink.h>
  26. #include <asiolink/internal/tcpdns.h>
  27. #include <asiolink/internal/udpdns.h>
  28. using namespace asio;
  29. using asio::ip::udp;
  30. using asio::ip::tcp;
  31. using namespace std;
  32. using namespace isc::dns;
  33. namespace asiolink {
  34. class IOServiceImpl {
  35. private:
  36. IOServiceImpl(const IOService& source);
  37. IOServiceImpl& operator=(const IOService& source);
  38. public:
  39. /// \brief The constructor
  40. IOServiceImpl() : io_service_() {};
  41. /// \brief The destructor.
  42. ~IOServiceImpl() {};
  43. //@}
  44. /// \brief Start the underlying event loop.
  45. ///
  46. /// This method does not return control to the caller until
  47. /// the \c stop() method is called via some handler.
  48. void run() { io_service_.run(); };
  49. /// \brief Run the underlying event loop for a single event.
  50. ///
  51. /// This method return control to the caller as soon as the
  52. /// first handler has completed. (If no handlers are ready when
  53. /// it is run, it will block until one is.)
  54. void run_one() { io_service_.run_one();} ;
  55. /// \brief Stop the underlying event loop.
  56. ///
  57. /// This will return the control to the caller of the \c run() method.
  58. void stop() { io_service_.stop();} ;
  59. /// \brief Return the native \c io_service object used in this wrapper.
  60. ///
  61. /// This is a short term work around to support other BIND 10 modules
  62. /// that share the same \c io_service with the authoritative server.
  63. /// It will eventually be removed once the wrapper interface is
  64. /// generalized.
  65. asio::io_service& get_io_service() { return io_service_; };
  66. private:
  67. asio::io_service io_service_;
  68. };
  69. IOService::IOService() {
  70. io_impl_ = new IOServiceImpl();
  71. }
  72. IOService::~IOService() {
  73. delete io_impl_;
  74. }
  75. void
  76. IOService::run() {
  77. io_impl_->run();
  78. }
  79. void
  80. IOService::run_one() {
  81. io_impl_->run_one();
  82. }
  83. void
  84. IOService::stop() {
  85. io_impl_->stop();
  86. }
  87. asio::io_service&
  88. IOService::get_io_service() {
  89. return (io_impl_->get_io_service());
  90. }
  91. class DNSServiceImpl {
  92. public:
  93. DNSServiceImpl(IOService& io_service, const char& port,
  94. const ip::address* v4addr, const ip::address* v6addr,
  95. SimpleCallback* checkin, DNSLookup* lookup,
  96. DNSAnswer* answer);
  97. //asio::io_service io_service_;
  98. void stop();
  99. typedef boost::shared_ptr<UDPServer> UDPServerPtr;
  100. typedef boost::shared_ptr<TCPServer> TCPServerPtr;
  101. UDPServerPtr udp4_server_;
  102. UDPServerPtr udp6_server_;
  103. TCPServerPtr tcp4_server_;
  104. TCPServerPtr tcp6_server_;
  105. };
  106. DNSServiceImpl::DNSServiceImpl(IOService& io_service_,
  107. const char& port,
  108. const ip::address* const v4addr,
  109. const ip::address* const v6addr,
  110. SimpleCallback* checkin,
  111. DNSLookup* lookup,
  112. DNSAnswer* answer) :
  113. udp4_server_(UDPServerPtr()), udp6_server_(UDPServerPtr()),
  114. tcp4_server_(TCPServerPtr()), tcp6_server_(TCPServerPtr())
  115. {
  116. uint16_t portnum;
  117. try {
  118. // XXX: SunStudio with stlport4 doesn't reject some invalid
  119. // representation such as "-1" by lexical_cast<uint16_t>, so
  120. // we convert it into a signed integer of a larger size and perform
  121. // range check ourselves.
  122. const int32_t portnum32 = boost::lexical_cast<int32_t>(&port);
  123. if (portnum32 < 0 || portnum32 > 65535) {
  124. isc_throw(IOError, "Invalid port number '" << &port);
  125. }
  126. portnum = portnum32;
  127. } catch (const boost::bad_lexical_cast& ex) {
  128. isc_throw(IOError, "Invalid port number '" << &port << "': " <<
  129. ex.what());
  130. }
  131. try {
  132. if (v4addr != NULL) {
  133. udp4_server_ = UDPServerPtr(new UDPServer(io_service_.get_io_service(),
  134. *v4addr, portnum,
  135. checkin, lookup, answer));
  136. (*udp4_server_)();
  137. tcp4_server_ = TCPServerPtr(new TCPServer(io_service_.get_io_service(),
  138. *v4addr, portnum,
  139. checkin, lookup, answer));
  140. (*tcp4_server_)();
  141. }
  142. if (v6addr != NULL) {
  143. udp6_server_ = UDPServerPtr(new UDPServer(io_service_.get_io_service(),
  144. *v6addr, portnum,
  145. checkin, lookup, answer));
  146. (*udp6_server_)();
  147. tcp6_server_ = TCPServerPtr(new TCPServer(io_service_.get_io_service(),
  148. *v6addr, portnum,
  149. checkin, lookup, answer));
  150. (*tcp6_server_)();
  151. }
  152. } catch (const asio::system_error& err) {
  153. // We need to catch and convert any ASIO level exceptions.
  154. // This can happen for unavailable address, binding a privilege port
  155. // without the privilege, etc.
  156. isc_throw(IOError, "Failed to initialize network servers: " <<
  157. err.what());
  158. }
  159. }
  160. DNSService::DNSService(IOService& io_service,
  161. const char& port, const char& address,
  162. SimpleCallback* checkin,
  163. DNSLookup* lookup,
  164. DNSAnswer* answer) :
  165. impl_(NULL), io_service_(io_service)
  166. {
  167. error_code err;
  168. const ip::address addr = ip::address::from_string(&address, err);
  169. if (err) {
  170. isc_throw(IOError, "Invalid IP address '" << &address << "': "
  171. << err.message());
  172. }
  173. impl_ = new DNSServiceImpl(io_service, port,
  174. addr.is_v4() ? &addr : NULL,
  175. addr.is_v6() ? &addr : NULL,
  176. checkin, lookup, answer);
  177. }
  178. DNSService::DNSService(IOService& io_service,
  179. const char& port,
  180. const bool use_ipv4, const bool use_ipv6,
  181. SimpleCallback* checkin,
  182. DNSLookup* lookup,
  183. DNSAnswer* answer) :
  184. impl_(NULL), io_service_(io_service)
  185. {
  186. const ip::address v4addr_any = ip::address(ip::address_v4::any());
  187. const ip::address* const v4addrp = use_ipv4 ? &v4addr_any : NULL;
  188. const ip::address v6addr_any = ip::address(ip::address_v6::any());
  189. const ip::address* const v6addrp = use_ipv6 ? &v6addr_any : NULL;
  190. impl_ = new DNSServiceImpl(io_service, port, v4addrp, v6addrp, checkin, lookup, answer);
  191. }
  192. DNSService::~DNSService() {
  193. delete impl_;
  194. }
  195. RecursiveQuery::RecursiveQuery(DNSService& dns_service, const char& forward,
  196. uint16_t port) :
  197. dns_service_(dns_service), ns_addr_(&forward), port_(port)
  198. {}
  199. void
  200. RecursiveQuery::sendQuery(const Question& question, OutputBufferPtr buffer,
  201. DNSServer* server)
  202. {
  203. // XXX: eventually we will need to be able to determine whether
  204. // the message should be sent via TCP or UDP, or sent initially via
  205. // UDP and then fall back to TCP on failure, but for the moment
  206. // we're only going to handle UDP.
  207. asio::io_service& io = dns_service_.get_io_service();
  208. UDPQuery q(io, question, ns_addr_, port_, buffer, server);
  209. io.post(q);
  210. }
  211. }