asiolink.cc 6.52 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 46
class IOServiceImpl {
public:
47 48
    IOServiceImpl(const char& port,
                  const ip::address* v4addr, const ip::address* v6addr,
49
                  SimpleCallback* checkin, DNSLookup* lookup,
50
                  DNSAnswer* answer);
51
    asio::io_service io_service_;
52 53 54 55 56 57 58

    typedef boost::shared_ptr<UDPServer> UDPServerPtr;
    typedef boost::shared_ptr<TCPServer> TCPServerPtr;
    UDPServerPtr udp4_server_;
    UDPServerPtr udp6_server_;
    TCPServerPtr tcp4_server_;
    TCPServerPtr tcp6_server_;
59 60
};

61
IOServiceImpl::IOServiceImpl(const char& port,
62
                             const ip::address* const v4addr,
63
                             const ip::address* const v6addr,
64
                             SimpleCallback* checkin,
65 66
                             DNSLookup* lookup,
                             DNSAnswer* answer) :
67 68
    udp4_server_(UDPServerPtr()), udp6_server_(UDPServerPtr()),
    tcp4_server_(TCPServerPtr()), tcp6_server_(TCPServerPtr())
69
{
70
    uint16_t portnum;
Evan Hunt's avatar
Evan Hunt committed
71
    try {
72 73 74 75
        // 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
76
        const int32_t portnum32 = boost::lexical_cast<int32_t>(&port);
77 78 79 80
        if (portnum32 < 0 || portnum32 > 65535) {
            isc_throw(IOError, "Invalid port number '" << &port);
        }
        portnum = portnum32;
81
    } catch (const boost::bad_lexical_cast& ex) {
82 83
        isc_throw(IOError, "Invalid port number '" << &port << "': " <<
                  ex.what());
84
    }
Evan Hunt's avatar
Evan Hunt committed
85

86
    try {
87
        if (v4addr != NULL) {
88 89
            udp4_server_ = UDPServerPtr(new UDPServer(io_service_,
                                                      *v4addr, portnum,
90
                                                      checkin, lookup, answer));
91 92 93
            (*udp4_server_)();
            tcp4_server_ = TCPServerPtr(new TCPServer(io_service_,
                                                      *v4addr, portnum,
94
                                                      checkin, lookup, answer));
95
            (*tcp4_server_)();
96
        }
97
        if (v6addr != NULL) {
98 99
            udp6_server_ = UDPServerPtr(new UDPServer(io_service_,
                                                      *v6addr, portnum,
100
                                                      checkin, lookup, answer));
101 102 103
            (*udp6_server_)();
            tcp6_server_ = TCPServerPtr(new TCPServer(io_service_,
                                                      *v6addr, portnum,
104
                                                      checkin, lookup, answer));
105
            (*tcp6_server_)();
106 107 108 109 110 111 112
        }
    } 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());
113 114
    }
}
Evan Hunt's avatar
Evan Hunt committed
115

116
IOService::IOService(const char& port, const char& address,
117
                     SimpleCallback* checkin,
118 119
                     DNSLookup* lookup,
                     DNSAnswer* answer) :
120 121 122 123 124 125 126
    impl_(NULL)
{
    error_code err;
    const ip::address addr = ip::address::from_string(&address, err);
    if (err) {
        isc_throw(IOError, "Invalid IP address '" << &address << "': "
                  << err.message());
127
    }
128

129
    impl_ = new IOServiceImpl(port,
130
                              addr.is_v4() ? &addr : NULL,
131
                              addr.is_v6() ? &addr : NULL,
132
                              checkin, lookup, answer);
133 134
}

135 136
IOService::IOService(const char& port,
                     const bool use_ipv4, const bool use_ipv6,
137
                     SimpleCallback* checkin,
138 139
                     DNSLookup* lookup,
                     DNSAnswer* answer) :
140 141
    impl_(NULL)
{
142 143 144 145
    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;
146
    impl_ = new IOServiceImpl(port, v4addrp, v6addrp, checkin, lookup, answer);
147 148 149 150 151 152 153 154 155 156 157
}

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

void
IOService::run() {
    impl_->io_service_.run();
}

158 159 160 161 162
void
IOService::run_one() {
    impl_->io_service_.run_one();
}

163 164 165 166
void
IOService::stop() {
    impl_->io_service_.stop();
}
167 168 169

asio::io_service&
IOService::get_io_service() {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
170
    return (impl_->io_service_);
171
}
172

173 174
RecursiveQuery::RecursiveQuery(IOService& io_service, const char& forward,
                               uint16_t port) :
175 176
    io_service_(io_service), ns_addr_(&forward), port_(port) 
{}
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191

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.
    asio::io_service& io = io_service_.get_io_service();
    UDPQuery q(io, question, ns_addr_, port_, buffer, server);
    io.post(q);
}

192
}