asiolink.cc 8.34 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.

// $Id$

#include <config.h>

19
#include <unistd.h>             // for some IPC/network system calls
20
21
22
#include <sys/socket.h>
#include <netinet/in.h>

23
#include <asio.hpp>
Evan Hunt's avatar
Evan Hunt committed
24
#include <boost/lexical_cast.hpp>
25
26
#include <boost/bind.hpp>

27
28
#include <boost/shared_ptr.hpp>

29
30
31
#include <dns/buffer.h>
#include <dns/message.h>

32
33
34
#include <asiolink/asiolink.h>
#include <asiolink/internal/tcpdns.h>
#include <asiolink/internal/udpdns.h>
35
36

using namespace asio;
37
38
using asio::ip::udp;
using asio::ip::tcp;
39

40
using namespace std;
41
using namespace isc::dns;
42

43
namespace asiolink {
44

45
class IOServiceImpl {
46
47
48
private:
    IOServiceImpl(const IOService& source);
    IOServiceImpl& operator=(const IOService& source);
49
public:
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
    /// \brief The constructor
    IOServiceImpl() : io_service_() {};
    /// \brief The destructor.
    ~IOServiceImpl() {};
    //@}

    /// \brief Start the underlying event loop.
    ///
    /// This method does not return control to the caller until
    /// the \c stop() method is called via some handler.
    void run() { io_service_.run(); };

    /// \brief Run the underlying event loop for a single event.
    ///
    /// This method return control to the caller as soon as the
    /// first handler has completed.  (If no handlers are ready when
    /// it is run, it will block until one is.)
    void run_one() { io_service_.run_one();} ;

    /// \brief Stop the underlying event loop.
    ///
    /// This will return the control to the caller of the \c run() method.
    void stop() { io_service_.stop();} ;

    /// \brief Return the native \c io_service object used in this wrapper.
    ///
    /// This is a short term work around to support other BIND 10 modules
    /// that share the same \c io_service with the authoritative server.
    /// It will eventually be removed once the wrapper interface is
    /// generalized.
    asio::io_service& get_io_service() { return io_service_; };
private:
    asio::io_service io_service_;
};

IOService::IOService() {
    io_impl_ = new IOServiceImpl();
}

IOService::~IOService() {
    delete io_impl_;
}

void
IOService::run() {
    io_impl_->run();
}

void
IOService::run_one() {
    io_impl_->run_one();
}

void
IOService::stop() {
    io_impl_->stop();
}

asio::io_service&
IOService::get_io_service() {
Jelte Jansen's avatar
Jelte Jansen committed
110
    return (io_impl_->get_io_service());
111
112
113
114
115
}

class DNSServiceImpl {
public:
    DNSServiceImpl(IOService& io_service, const char& port,
116
                  const ip::address* v4addr, const ip::address* v6addr,
117
                  SimpleCallback* checkin, DNSLookup* lookup,
118
                  DNSAnswer* answer);
119
    //asio::io_service io_service_;
120

121
    void stop();
122
123
124
125
126
127
    typedef boost::shared_ptr<UDPServer> UDPServerPtr;
    typedef boost::shared_ptr<TCPServer> TCPServerPtr;
    UDPServerPtr udp4_server_;
    UDPServerPtr udp6_server_;
    TCPServerPtr tcp4_server_;
    TCPServerPtr tcp6_server_;
128
129
};

130
131
132
133
134
135
136
DNSServiceImpl::DNSServiceImpl(IOService& io_service_,
                               const char& port,
                               const ip::address* const v4addr,
                               const ip::address* const v6addr,
                               SimpleCallback* checkin,
                               DNSLookup* lookup,
                               DNSAnswer* answer) :
137
138
    udp4_server_(UDPServerPtr()), udp6_server_(UDPServerPtr()),
    tcp4_server_(TCPServerPtr()), tcp6_server_(TCPServerPtr())
139
{
140
    uint16_t portnum;
Evan Hunt's avatar
Evan Hunt committed
141
    try {
142
143
144
145
        // XXX: SunStudio with stlport4 doesn't reject some invalid
        // representation such as "-1" by lexical_cast<uint16_t>, so
        // we convert it into a signed integer of a larger size and perform
        // range check ourselves.
JINMEI Tatuya's avatar
JINMEI Tatuya committed
146
        const int32_t portnum32 = boost::lexical_cast<int32_t>(&port);
147
148
149
150
        if (portnum32 < 0 || portnum32 > 65535) {
            isc_throw(IOError, "Invalid port number '" << &port);
        }
        portnum = portnum32;
151
    } catch (const boost::bad_lexical_cast& ex) {
152
153
        isc_throw(IOError, "Invalid port number '" << &port << "': " <<
                  ex.what());
154
    }
Evan Hunt's avatar
Evan Hunt committed
155

156
    try {
157
        if (v4addr != NULL) {
158
            udp4_server_ = UDPServerPtr(new UDPServer(io_service_.get_io_service(),
159
                                                      *v4addr, portnum,
160
                                                      checkin, lookup, answer));
161
            (*udp4_server_)();
162
            tcp4_server_ = TCPServerPtr(new TCPServer(io_service_.get_io_service(),
163
                                                      *v4addr, portnum,
164
                                                      checkin, lookup, answer));
165
            (*tcp4_server_)();
166
        }
167
        if (v6addr != NULL) {
168
            udp6_server_ = UDPServerPtr(new UDPServer(io_service_.get_io_service(),
169
                                                      *v6addr, portnum,
170
                                                      checkin, lookup, answer));
171
            (*udp6_server_)();
172
            tcp6_server_ = TCPServerPtr(new TCPServer(io_service_.get_io_service(),
173
                                                      *v6addr, portnum,
174
                                                      checkin, lookup, answer));
175
            (*tcp6_server_)();
176
177
178
179
180
181
182
        }
    } catch (const asio::system_error& err) {
        // We need to catch and convert any ASIO level exceptions.
        // This can happen for unavailable address, binding a privilege port
        // without the privilege, etc.
        isc_throw(IOError, "Failed to initialize network servers: " <<
                  err.what());
183
184
    }
}
Evan Hunt's avatar
Evan Hunt committed
185

186
187
188
189
190
191
DNSService::DNSService(IOService& io_service,
                       const char& port, const char& address,
                       SimpleCallback* checkin,
                       DNSLookup* lookup,
                       DNSAnswer* answer) :
    impl_(NULL), io_service_(io_service)
192
193
194
195
196
197
{
    error_code err;
    const ip::address addr = ip::address::from_string(&address, err);
    if (err) {
        isc_throw(IOError, "Invalid IP address '" << &address << "': "
                  << err.message());
198
    }
199

200
    impl_ = new DNSServiceImpl(io_service, port,
201
                              addr.is_v4() ? &addr : NULL,
202
                              addr.is_v6() ? &addr : NULL,
203
                              checkin, lookup, answer);
204
205
}

206
207
208
209
210
211
212
DNSService::DNSService(IOService& io_service,
                       const char& port,
                       const bool use_ipv4, const bool use_ipv6,
                       SimpleCallback* checkin,
                       DNSLookup* lookup,
                       DNSAnswer* answer) :
    impl_(NULL), io_service_(io_service)
213
{
214
215
216
217
    const ip::address v4addr_any = ip::address(ip::address_v4::any());
    const ip::address* const v4addrp = use_ipv4 ? &v4addr_any : NULL; 
    const ip::address v6addr_any = ip::address(ip::address_v6::any());
    const ip::address* const v6addrp = use_ipv6 ? &v6addr_any : NULL;
218
    impl_ = new DNSServiceImpl(io_service, port, v4addrp, v6addrp, checkin, lookup, answer);
219
220
}

221
DNSService::~DNSService() {
222
223
224
    delete impl_;
}

225
RecursiveQuery::RecursiveQuery(DNSService& dns_service, const char& forward,
226
                               uint16_t port) :
227
    dns_service_(dns_service), ns_addr_(&forward), port_(port) 
228
{}
229
230
231
232
233
234
235
236
237
238

void
RecursiveQuery::sendQuery(const Question& question, OutputBufferPtr buffer,
                          DNSServer* server)
{

    // XXX: eventually we will need to be able to determine whether
    // the message should be sent via TCP or UDP, or sent initially via
    // UDP and then fall back to TCP on failure, but for the moment
    // we're only going to handle UDP.
239
    asio::io_service& io = dns_service_.get_io_service();
240
241
242
243
    UDPQuery q(io, question, ns_addr_, port_, buffer, server);
    io.post(q);
}

244
}