Branch data Line data Source code
1 : : // Copyright (C) 2012 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 : :
15 : : #ifndef __SYNC_UDP_SERVER_H
16 : : #define __SYNC_UDP_SERVER_H 1
17 : :
18 : : #ifndef ASIO_HPP
19 : : #error "asio.hpp must be included before including this, see asiolink.h as to why"
20 : : #endif
21 : :
22 : : #include "dns_answer.h"
23 : : #include "dns_lookup.h"
24 : : #include "dns_server.h"
25 : :
26 : : #include <dns/message.h>
27 : : #include <asiolink/simple_callback.h>
28 : : #include <util/buffer.h>
29 : : #include <exceptions/exceptions.h>
30 : :
31 : : #include <boost/noncopyable.hpp>
32 : :
33 : : #include <stdint.h>
34 : :
35 : : namespace isc {
36 : : namespace asiodns {
37 : :
38 : : /// \brief An UDP server that doesn't asynchronous lookup handlers.
39 : : ///
40 : : /// That means, the lookup handler must provide the answer right away.
41 : : /// This allows for implementation with less overhead, compared with
42 : : /// the UDPClass.
43 : 30 : class SyncUDPServer : public DNSServer, public boost::noncopyable {
44 : : public:
45 : : /// \brief Constructor
46 : : /// \param io_service the asio::io_service to work with
47 : : /// \param fd the file descriptor of opened UDP socket
48 : : /// \param af address family, either AF_INET or AF_INET6
49 : : /// \param checkin the callbackprovider for non-DNS events
50 : : /// \param lookup the callbackprovider for DNS lookup events
51 : : /// \param answer the callbackprovider for DNS answer events
52 : : /// \throw isc::InvalidParameter if af is neither AF_INET nor AF_INET6
53 : : /// \throw isc::asiolink::IOError when a low-level error happens, like the
54 : : /// fd is not a valid descriptor.
55 : : SyncUDPServer(asio::io_service& io_service, const int fd, const int af,
56 : : isc::asiolink::SimpleCallback* checkin = NULL,
57 : : DNSLookup* lookup = NULL, DNSAnswer* answer = NULL);
58 : :
59 : : /// \brief Start the SyncUDPServer.
60 : : ///
61 : : /// This is the function operator to keep interface with other server
62 : : /// classes. They need that because they're coroutines.
63 : : virtual void operator()(asio::error_code ec = asio::error_code(),
64 : : size_t length = 0);
65 : :
66 : : /// \brief Calls the lookup callback
67 : 1 : virtual void asyncLookup() {
68 [ + - ]: 2 : isc_throw(Unexpected,
69 : : "SyncUDPServer doesn't support asyncLookup by design, use "
70 : : "UDPServer if you need it.");
71 : : }
72 : :
73 : : /// \brief Stop the running server
74 : : /// \note once the server stopped, it can't restart
75 : : virtual void stop();
76 : :
77 : : /// \brief Resume operation
78 : : ///
79 : : /// Note that unlike other servers, this one expects it to be called
80 : : /// directly from the lookup callback. If it isn't, the server will
81 : : /// throw an Unexpected exception (probably to the event loop, which
82 : : /// would usually lead to termination of the program, but that's OK,
83 : : /// as it would be serious programmer error).
84 : : ///
85 : : /// \param done Set this to true if the lookup action is done and
86 : : /// we have an answer
87 : : virtual void resume(const bool done);
88 : :
89 : : /// \brief Check if we have an answer
90 : : ///
91 : : /// \return true if we have an answer
92 : : virtual bool hasAnswer();
93 : :
94 : : /// \brief Clones the object
95 : : ///
96 : : /// Since cloning is for the use of coroutines, the synchronous UDP server
97 : : /// does not need to be cloned. Therefore supporting it would be needless
98 : : /// work, and trying to clone it would be a programmer error anyway, this
99 : : /// throws Unexpected.
100 : : ///
101 : : /// \return a newly allocated copy of this object
102 : 1 : virtual DNSServer* clone() {
103 [ + - ]: 2 : isc_throw(Unexpected, "SyncUDPServer can't be cloned.");
104 : : }
105 : : private:
106 : : // Internal state & buffers. We don't use the PIMPL idiom, as this class
107 : : // isn't usually used directly anyway.
108 : :
109 : : // Maximum size of incoming UDP packet
110 : : static const size_t MAX_LENGTH = 4096;
111 : : // Buffer for incoming data
112 : : uint8_t data_[MAX_LENGTH];
113 : : // The buffer to render the output to and send it.
114 : : // If it was OK to have just a buffer, not the wrapper class,
115 : : // we could reuse the data_
116 : : isc::util::OutputBufferPtr output_buffer_;
117 : : // Objects to hold the query message and the answer
118 : : isc::dns::MessagePtr query_, answer_;
119 : : // The socket used for the communication
120 : : std::auto_ptr<asio::ip::udp::socket> socket_;
121 : : // The event loop we use
122 : : asio::io_service& io_;
123 : : // Place the socket puts the sender of a packet when it is received
124 : : asio::ip::udp::endpoint sender_;
125 : : // Callbacks
126 : : const asiolink::SimpleCallback* checkin_callback_;
127 : : const DNSLookup* lookup_callback_;
128 : : const DNSAnswer* answer_callback_;
129 : : // Answers from the lookup callback (not sent directly, but signalled
130 : : // through resume()
131 : : bool resume_called_, done_;
132 : : // This turns true when the server stops. Allows for not sending the
133 : : // answer after we closed the socket.
134 : : bool stopped_;
135 : :
136 : : // Auxiliary functions
137 : :
138 : : // Schedule next read on the socket. Just a wrapper around
139 : : // socket_->async_read_from with the correct parameters.
140 : : void scheduleRead();
141 : : // Callback from the socket's read call (called when there's an error or
142 : : // when a new packet comes).
143 : : void handleRead(const asio::error_code& ec, const size_t length);
144 : : };
145 : :
146 : : } // namespace asiodns
147 : : } // namespace isc
148 : : #endif // __SYNC_UDP_SERVER_H
|