udpdns.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  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. #include <config.h>
  15. #include <unistd.h> // for some IPC/network system calls
  16. #include <sys/socket.h>
  17. #include <netinet/in.h>
  18. #include <boost/bind.hpp>
  19. #include <asio.hpp>
  20. #include <asio/deadline_timer.hpp>
  21. #include <memory>
  22. #include <boost/shared_ptr.hpp>
  23. #include <boost/date_time/posix_time/posix_time_types.hpp>
  24. #include <dns/buffer.h>
  25. #include <dns/message.h>
  26. #include <dns/messagerenderer.h>
  27. #include <log/dummylog.h>
  28. #include <dns/opcode.h>
  29. #include <dns/rcode.h>
  30. #include <asiolink.h>
  31. #include <internal/coroutine.h>
  32. #include <internal/udpdns.h>
  33. using namespace asio;
  34. using asio::ip::udp;
  35. using asio::ip::tcp;
  36. using isc::log::dlog;
  37. using namespace std;
  38. using namespace isc::dns;
  39. namespace asiolink {
  40. /*
  41. * Some of the member variables here are shared_ptrs and some are
  42. * auto_ptrs. There will be one instance of Data for the lifetime
  43. * of packet. The variables that are state only for a single packet
  44. * use auto_ptr, as it is more lightweight. In the case of shared
  45. * configuration (eg. the callbacks, socket), we use shared_ptrs.
  46. */
  47. struct UDPServer::Data {
  48. /*
  49. * Constructor from parameters passed to UDPServer constructor.
  50. * This instance will not be used to retrieve and answer the actual
  51. * query, it will only hold parameters until we wait for the
  52. * first packet. But we do initialize the socket in here.
  53. */
  54. Data(io_service& io_service, const ip::address& addr, const uint16_t port,
  55. SimpleCallback* checkin, DNSLookup* lookup, DNSAnswer* answer) :
  56. io_(io_service), done_(false), checkin_callback_(checkin),
  57. lookup_callback_(lookup), answer_callback_(answer)
  58. {
  59. // We must use different instantiations for v4 and v6;
  60. // otherwise ASIO will bind to both
  61. udp proto = addr.is_v4() ? udp::v4() : udp::v6();
  62. socket_.reset(new udp::socket(io_service, proto));
  63. socket_->set_option(socket_base::reuse_address(true));
  64. if (addr.is_v6()) {
  65. socket_->set_option(asio::ip::v6_only(true));
  66. }
  67. socket_->bind(udp::endpoint(addr, port));
  68. }
  69. /*
  70. * Copy constructor. Default one would probably do, but it is unnecessary
  71. * to copy many of the member variables every time we fork to handle
  72. * another packet.
  73. *
  74. * We also allocate data for receiving the packet here.
  75. */
  76. Data(const Data& other) :
  77. io_(other.io_), socket_(other.socket_), done_(false),
  78. checkin_callback_(other.checkin_callback_),
  79. lookup_callback_(other.lookup_callback_),
  80. answer_callback_(other.answer_callback_)
  81. {
  82. // Instantiate the data buffer and endpoint that will
  83. // be used by the asynchronous receive call.
  84. data_.reset(new char[MAX_LENGTH]);
  85. sender_.reset(new udp::endpoint());
  86. }
  87. // The ASIO service object
  88. asio::io_service& io_;
  89. // Class member variables which are dynamic, and changes to which
  90. // need to accessible from both sides of a coroutine fork or from
  91. // outside of the coroutine (i.e., from an asynchronous I/O call),
  92. // should be declared here as pointers and allocated in the
  93. // constructor or in the coroutine. This allows state information
  94. // to persist when an individual copy of the coroutine falls out
  95. // scope while waiting for an event, *so long as* there is another
  96. // object that is referencing the same data. As a side-benefit, using
  97. // pointers also reduces copy overhead for coroutine objects.
  98. //
  99. // Note: Currently these objects are allocated by "new" in the
  100. // constructor, or in the function operator while processing a query.
  101. // Repeated allocations from the heap for every incoming query is
  102. // clearly a performance issue; this must be optimized in the future.
  103. // The plan is to have a structure pre-allocate several "Data"
  104. // objects which can be pulled off a free list and placed on an in-use
  105. // list whenever a query comes in. This will serve the dual purpose
  106. // of improving performance and guaranteeing that state information
  107. // will *not* be destroyed when any one instance of the coroutine
  108. // falls out of scope while waiting for an event.
  109. //
  110. // Socket used to for listen for queries. Created in the
  111. // constructor and stored in a shared_ptr because socket objects
  112. // are not copyable.
  113. boost::shared_ptr<asio::ip::udp::socket> socket_;
  114. // The ASIO-internal endpoint object representing the client
  115. std::auto_ptr<asio::ip::udp::endpoint> sender_;
  116. // \c IOMessage and \c Message objects to be passed to the
  117. // DNS lookup and answer providers
  118. std::auto_ptr<asiolink::IOMessage> io_message_;
  119. // The original query as sent by the client
  120. isc::dns::MessagePtr query_message_;
  121. // The response message we are building
  122. isc::dns::MessagePtr answer_message_;
  123. // The buffer into which the response is written
  124. isc::dns::OutputBufferPtr respbuf_;
  125. // The buffer into which the query packet is written
  126. boost::shared_array<char> data_;
  127. // State information that is entirely internal to a given instance
  128. // of the coroutine can be declared here.
  129. size_t bytes_;
  130. bool done_;
  131. // Callback functions provided by the caller
  132. const SimpleCallback* checkin_callback_;
  133. const DNSLookup* lookup_callback_;
  134. const DNSAnswer* answer_callback_;
  135. std::auto_ptr<IOEndpoint> peer_;
  136. std::auto_ptr<IOSocket> iosock_;
  137. };
  138. /// The following functions implement the \c UDPServer class.
  139. ///
  140. /// The constructor. It just creates new internal state object
  141. /// and lets it handle the initialization.
  142. UDPServer::UDPServer(io_service& io_service, const ip::address& addr,
  143. const uint16_t port, SimpleCallback* checkin, DNSLookup* lookup,
  144. DNSAnswer* answer) :
  145. data_(new Data(io_service, addr, port, checkin, lookup, answer))
  146. { }
  147. /// The function operator is implemented with the "stackless coroutine"
  148. /// pattern; see internal/coroutine.h for details.
  149. void
  150. UDPServer::operator()(error_code ec, size_t length) {
  151. /// Because the coroutine reeentry block is implemented as
  152. /// a switch statement, inline variable declarations are not
  153. /// permitted. Certain variables used below can be declared here.
  154. CORO_REENTER (this) {
  155. do {
  156. /*
  157. * This is preparation for receiving a packet. We get a new
  158. * state object for the lifetime of the next packet to come.
  159. * It allocates the buffers to receive data into.
  160. */
  161. data_.reset(new Data(*data_));
  162. do {
  163. // Begin an asynchronous receive, then yield.
  164. // When the receive event is posted, the coroutine
  165. // will resume immediately after this point.
  166. CORO_YIELD data_->socket_->async_receive_from(
  167. buffer(data_->data_.get(), MAX_LENGTH), *data_->sender_,
  168. *this);
  169. } while (ec || length == 0);
  170. data_->bytes_ = length;
  171. /*
  172. * We fork the coroutine now. One (the child) will keep
  173. * the current state and handle the packet, then die and
  174. * drop ownership of the state. The other (parent) will just
  175. * go into the loop again and replace the current state with
  176. * a new one for a new object.
  177. *
  178. * Actually, both of the coroutines will be a copy of this
  179. * one, but that's just internal implementation detail.
  180. */
  181. CORO_FORK data_->io_.post(UDPServer(*this));
  182. } while (is_parent());
  183. // Create an \c IOMessage object to store the query.
  184. //
  185. // (XXX: It would be good to write a factory function
  186. // that would quickly generate an IOMessage object without
  187. // all these calls to "new".)
  188. data_->peer_.reset(new UDPEndpoint(*data_->sender_));
  189. data_->iosock_.reset(new UDPSocket(*data_->socket_));
  190. data_->io_message_.reset(new IOMessage(data_->data_.get(),
  191. data_->bytes_, *data_->iosock_, *data_->peer_));
  192. // Perform any necessary operations prior to processing an incoming
  193. // query (e.g., checking for queued configuration messages).
  194. //
  195. // (XXX: it may be a performance issue to check in for every single
  196. // incoming query; we may wish to throttle this in the future.)
  197. if (data_->checkin_callback_ != NULL) {
  198. (*data_->checkin_callback_)(*data_->io_message_);
  199. }
  200. // If we don't have a DNS Lookup provider, there's no point in
  201. // continuing; we exit the coroutine permanently.
  202. if (data_->lookup_callback_ == NULL) {
  203. CORO_YIELD return;
  204. }
  205. // Instantiate objects that will be needed by the
  206. // asynchronous DNS lookup and/or by the send call.
  207. data_->respbuf_.reset(new OutputBuffer(0));
  208. data_->query_message_.reset(new Message(Message::PARSE));
  209. data_->answer_message_.reset(new Message(Message::RENDER));
  210. // Schedule a DNS lookup, and yield. When the lookup is
  211. // finished, the coroutine will resume immediately after
  212. // this point.
  213. CORO_YIELD data_->io_.post(AsyncLookup<UDPServer>(*this));
  214. dlog("[XX] got an answer");
  215. // The 'done_' flag indicates whether we have an answer
  216. // to send back. If not, exit the coroutine permanently.
  217. if (!data_->done_) {
  218. CORO_YIELD return;
  219. }
  220. // Call the DNS answer provider to render the answer into
  221. // wire format
  222. (*data_->answer_callback_)(*data_->io_message_, data_->query_message_,
  223. data_->answer_message_, data_->respbuf_);
  224. // Begin an asynchronous send, and then yield. When the
  225. // send completes, we will resume immediately after this point
  226. // (though we have nothing further to do, so the coroutine
  227. // will simply exit at that time).
  228. CORO_YIELD data_->socket_->async_send_to(
  229. buffer(data_->respbuf_->getData(), data_->respbuf_->getLength()),
  230. *data_->sender_, *this);
  231. }
  232. }
  233. /// Call the DNS lookup provider. (Expected to be called by the
  234. /// AsyncLookup<UDPServer> handler.)
  235. void
  236. UDPServer::asyncLookup() {
  237. (*data_->lookup_callback_)(*data_->io_message_,
  238. data_->query_message_, data_->answer_message_, data_->respbuf_, this);
  239. }
  240. /// Post this coroutine on the ASIO service queue so that it will
  241. /// resume processing where it left off. The 'done' parameter indicates
  242. /// whether there is an answer to return to the client.
  243. void
  244. UDPServer::resume(const bool done) {
  245. data_->done_ = done;
  246. data_->io_.post(*this);
  247. }
  248. bool
  249. UDPServer::hasAnswer() {
  250. return (data_->done_);
  251. }
  252. // Private UDPQuery data (see internal/udpdns.h for reasons)
  253. struct UDPQuery::PrivateData {
  254. // Socket we send query to and expect reply from there
  255. udp::socket socket;
  256. // Where was the query sent
  257. udp::endpoint remote;
  258. // What we ask the server
  259. Question question;
  260. // We will store the answer here
  261. OutputBufferPtr buffer;
  262. OutputBufferPtr msgbuf;
  263. // Temporary buffer for answer
  264. boost::shared_array<char> data;
  265. // This will be called when the data arrive or timeouts
  266. Callback* callback;
  267. // Did we already stop operating (data arrived, we timed out, someone
  268. // called stop). This can be so when we are cleaning up/there are
  269. // still pointers to us.
  270. bool stopped;
  271. // Timer to measure timeouts.
  272. deadline_timer timer;
  273. // How many milliseconds are we willing to wait for answer?
  274. int timeout;
  275. PrivateData(io_service& service,
  276. const udp::socket::protocol_type& protocol, const Question &q,
  277. OutputBufferPtr b, Callback *c) :
  278. socket(service, protocol),
  279. question(q),
  280. buffer(b),
  281. msgbuf(new OutputBuffer(512)),
  282. callback(c),
  283. stopped(false),
  284. timer(service)
  285. { }
  286. };
  287. /// The following functions implement the \c UDPQuery class.
  288. ///
  289. /// The constructor
  290. UDPQuery::UDPQuery(io_service& io_service,
  291. const Question& q, const IOAddress& addr, uint16_t port,
  292. OutputBufferPtr buffer, Callback *callback, int timeout) :
  293. data_(new PrivateData(io_service,
  294. addr.getFamily() == AF_INET ? udp::v4() : udp::v6(), q, buffer,
  295. callback))
  296. {
  297. data_->remote = UDPEndpoint(addr, port).getASIOEndpoint();
  298. data_->timeout = timeout;
  299. }
  300. /// The function operator is implemented with the "stackless coroutine"
  301. /// pattern; see internal/coroutine.h for details.
  302. void
  303. UDPQuery::operator()(error_code ec, size_t length) {
  304. if (ec || data_->stopped) {
  305. return;
  306. }
  307. CORO_REENTER (this) {
  308. /// Generate the upstream query and render it to wire format
  309. /// This is done in a different scope to allow inline variable
  310. /// declarations.
  311. {
  312. Message msg(Message::RENDER);
  313. // XXX: replace with boost::random or some other suitable PRNG
  314. msg.setQid(0);
  315. msg.setOpcode(Opcode::QUERY());
  316. msg.setRcode(Rcode::NOERROR());
  317. msg.setHeaderFlag(Message::HEADERFLAG_RD);
  318. msg.addQuestion(data_->question);
  319. MessageRenderer renderer(*data_->msgbuf);
  320. msg.toWire(renderer);
  321. dlog("Sending " + msg.toText() + " to " +
  322. data_->remote.address().to_string());
  323. }
  324. // If we timeout, we stop, which will shutdown everything and
  325. // cancel all other attempts to run inside the coroutine
  326. if (data_->timeout != -1) {
  327. data_->timer.expires_from_now(boost::posix_time::milliseconds(
  328. data_->timeout));
  329. data_->timer.async_wait(boost::bind(&UDPQuery::stop, *this,
  330. TIME_OUT));
  331. }
  332. // Begin an asynchronous send, and then yield. When the
  333. // send completes, we will resume immediately after this point.
  334. CORO_YIELD data_->socket.async_send_to(buffer(data_->msgbuf->getData(),
  335. data_->msgbuf->getLength()), data_->remote, *this);
  336. /// Allocate space for the response. (XXX: This should be
  337. /// optimized by maintaining a free list of pre-allocated blocks)
  338. data_->data.reset(new char[MAX_LENGTH]);
  339. /// Begin an asynchronous receive, and yield. When the receive
  340. /// completes, we will resume immediately after this point.
  341. CORO_YIELD data_->socket.async_receive_from(buffer(data_->data.get(),
  342. MAX_LENGTH), data_->remote, *this);
  343. // The message is not rendered yet, so we can't print it easilly
  344. dlog("Received response from " + data_->remote.address().to_string());
  345. /// Copy the answer into the response buffer. (XXX: If the
  346. /// OutputBuffer object were made to meet the requirements of
  347. /// a MutableBufferSequence, then it could be written to directly
  348. /// by async_recieve_from() and this additional copy step would
  349. /// be unnecessary.)
  350. data_->buffer->writeData(data_->data.get(), length);
  351. /// We are done
  352. stop(SUCCESS);
  353. }
  354. }
  355. void
  356. UDPQuery::stop(Result result) {
  357. if (!data_->stopped) {
  358. switch (result) {
  359. case TIME_OUT:
  360. dlog("Query timed out");
  361. break;
  362. case STOPPED:
  363. dlog("Query stopped");
  364. break;
  365. default:;
  366. }
  367. data_->stopped = true;
  368. data_->socket.cancel();
  369. data_->socket.close();
  370. data_->timer.cancel();
  371. if (data_->callback) {
  372. (*data_->callback)(result);
  373. }
  374. }
  375. }
  376. }