2010-09-30 06:40:35 +00:00
|
|
|
// 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>
|
|
|
|
|
|
|
|
#include <unistd.h> // for some IPC/network system calls
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
|
|
|
|
#include <asio.hpp>
|
|
|
|
#include <asio/ip/address.hpp>
|
|
|
|
|
2010-09-30 06:40:42 +00:00
|
|
|
#include <boost/array.hpp>
|
2010-09-30 06:40:35 +00:00
|
|
|
#include <boost/lexical_cast.hpp>
|
|
|
|
#include <boost/shared_ptr.hpp>
|
|
|
|
|
|
|
|
#include <dns/buffer.h>
|
|
|
|
#include <dns/message.h>
|
|
|
|
#include <dns/messagerenderer.h>
|
|
|
|
|
|
|
|
#include <asiolink.h>
|
|
|
|
#include <internal/coroutine.h>
|
|
|
|
#include <internal/tcpdns.h>
|
|
|
|
|
|
|
|
using namespace asio;
|
|
|
|
using asio::ip::udp;
|
|
|
|
using asio::ip::tcp;
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
using namespace isc::dns;
|
|
|
|
|
|
|
|
namespace asiolink {
|
|
|
|
|
|
|
|
IOAddress
|
|
|
|
TCPEndpoint::getAddress() const {
|
|
|
|
return (asio_endpoint_.address());
|
|
|
|
}
|
|
|
|
|
|
|
|
uint16_t
|
|
|
|
TCPEndpoint::getPort() const {
|
|
|
|
return (asio_endpoint_.port());
|
|
|
|
}
|
|
|
|
|
|
|
|
short
|
|
|
|
TCPEndpoint::getProtocol() const {
|
|
|
|
return (asio_endpoint_.protocol().protocol());
|
|
|
|
}
|
|
|
|
|
|
|
|
short
|
|
|
|
TCPEndpoint::getFamily() const {
|
|
|
|
return (asio_endpoint_.protocol().family());
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
TCPSocket::getNative() const {
|
|
|
|
return (socket_.native());
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
TCPSocket::getProtocol() const {
|
|
|
|
return (IPPROTO_TCP);
|
|
|
|
}
|
|
|
|
|
|
|
|
TCPServer::TCPServer(io_service& io_service,
|
|
|
|
const ip::address& addr, const uint16_t port,
|
|
|
|
CheckinProvider* checkin, DNSProvider* process) :
|
2010-09-30 06:40:42 +00:00
|
|
|
respbuf_(0), lenbuf_(TCP_MESSAGE_LENGTHSIZE),
|
2010-09-30 06:40:35 +00:00
|
|
|
checkin_callback_(checkin), dns_callback_(process)
|
|
|
|
{
|
|
|
|
tcp::endpoint endpoint(addr, port);
|
|
|
|
acceptor_.reset(new tcp::acceptor(io_service));
|
|
|
|
acceptor_->open(endpoint.protocol());
|
2010-09-30 06:40:42 +00:00
|
|
|
// Set v6-only (we use a separate instantiation for v4,
|
2010-09-30 06:40:35 +00:00
|
|
|
// otherwise asio will bind to both v4 and v6
|
|
|
|
if (addr.is_v6()) {
|
|
|
|
acceptor_->set_option(ip::v6_only(true));
|
|
|
|
}
|
|
|
|
acceptor_->set_option(tcp::acceptor::reuse_address(true));
|
|
|
|
acceptor_->bind(endpoint);
|
|
|
|
acceptor_->listen();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TCPServer::operator()(error_code ec, size_t length) {
|
|
|
|
if (ec) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-09-30 06:40:42 +00:00
|
|
|
bool done = false;
|
2010-09-30 06:40:35 +00:00
|
|
|
CORO_REENTER (this) {
|
|
|
|
do {
|
|
|
|
socket_.reset(new tcp::socket(acceptor_->get_io_service()));
|
|
|
|
CORO_YIELD acceptor_->async_accept(*socket_, *this);
|
|
|
|
CORO_FORK TCPServer(*this)();
|
2010-09-30 06:40:42 +00:00
|
|
|
} while (is_child());
|
2010-09-30 06:40:35 +00:00
|
|
|
|
2010-09-30 06:40:42 +00:00
|
|
|
// Perform any necessary operations prior to processing an incoming
|
|
|
|
// packet (e.g., checking for queued configuration messages).
|
2010-09-30 06:40:35 +00:00
|
|
|
//
|
2010-09-30 06:40:42 +00:00
|
|
|
// (XXX: it may be a performance issue to have this called for
|
|
|
|
// every single incoming packet; we may wish to throttle it somehow
|
|
|
|
// in the future.)
|
2010-09-30 06:40:35 +00:00
|
|
|
if (checkin_callback_ != NULL) {
|
|
|
|
(*checkin_callback_)();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Instantiate the data buffer that will be used by the
|
|
|
|
// asynchronous read call.
|
|
|
|
data_ = boost::shared_ptr<char>(new char[MAX_LENGTH]);
|
|
|
|
CORO_YIELD async_read(*socket_, asio::buffer(data_.get(),
|
|
|
|
TCP_MESSAGE_LENGTHSIZE),
|
|
|
|
*this);
|
|
|
|
|
|
|
|
CORO_YIELD {
|
|
|
|
InputBuffer dnsbuffer((const void *) data_.get(), length);
|
|
|
|
uint16_t msglen = dnsbuffer.readUint16();
|
|
|
|
async_read(*socket_, asio::buffer(data_.get(), msglen), *this);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stop here if we don't have a DNS callback function
|
|
|
|
if (dns_callback_ == NULL) {
|
|
|
|
CORO_YIELD return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Instantiate the objects that will be needed by the
|
|
|
|
// DNS callback and the asynchronous write calls.
|
2010-09-30 06:40:42 +00:00
|
|
|
respbuf_.clear();
|
|
|
|
renderer_.reset(new MessageRenderer(respbuf_));
|
|
|
|
|
|
|
|
// Process the DNS message. (Must be done in a separate scope
|
|
|
|
// because CORO_REENTER is implemented with a switch statement
|
|
|
|
// and inline variable declaration isn't allowed.)
|
|
|
|
{
|
|
|
|
TCPEndpoint peer(socket_->remote_endpoint());
|
|
|
|
TCPSocket iosock(*socket_);
|
|
|
|
IOMessage io_message(data_.get(), length, iosock, peer);
|
|
|
|
Message message(Message::PARSE);
|
|
|
|
done = (*dns_callback_)(io_message, message, *renderer_);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!done) {
|
2010-09-30 06:40:35 +00:00
|
|
|
CORO_YIELD return;
|
|
|
|
}
|
|
|
|
|
2010-09-30 06:40:42 +00:00
|
|
|
CORO_YIELD {
|
|
|
|
lenbuf_.clear();
|
|
|
|
lenbuf_.writeUint16(respbuf_.getLength());
|
|
|
|
boost::array<const_buffer,2> bufs;
|
|
|
|
bufs[0] = buffer(lenbuf_.getData(), lenbuf_.getLength());
|
|
|
|
bufs[1] = buffer(respbuf_.getData(), respbuf_.getLength());
|
|
|
|
async_write(*socket_, bufs, *this);
|
|
|
|
}
|
2010-09-30 06:40:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|