Commit 43fda10b authored by Michal 'vorner' Vaner's avatar Michal 'vorner' Vaner
Browse files

Merge branch 'work/sock/cppclient' into scfinal

parents 65e86785 c836c770
......@@ -49,6 +49,7 @@
#include <asiolink/asiolink.h>
#include <log/logger_support.h>
#include <server_common/keyring.h>
#include <server_common/socket_request.h>
using namespace std;
using namespace isc::asiodns;
......@@ -168,6 +169,8 @@ main(int argc, char* argv[]) {
my_config_handler,
my_command_handler, false);
LOG_DEBUG(auth_logger, DBG_AUTH_START, AUTH_CONFIG_CHANNEL_ESTABLISHED);
// Initialize the Socket Requestor
isc::server_common::SocketRequestor::init(*config_session);
xfrin_session = new Session(io_service.get_io_service());
LOG_DEBUG(auth_logger, DBG_AUTH_START, AUTH_XFRIN_CHANNEL_CREATED);
......
......@@ -41,6 +41,7 @@
#include <testutils/dnsmessage_test.h>
#include <testutils/srv_test.h>
#include <testutils/portconfig.h>
#include <testutils/socket_request.h>
using namespace std;
using namespace isc::cc;
......@@ -68,7 +69,8 @@ protected:
AuthSrvTest() :
dnss_(ios_, NULL, NULL, NULL),
server(true, xfrout),
rrclass(RRClass::IN())
rrclass(RRClass::IN()),
sock_requestor_(dnss_, address_store_, 53210)
{
server.setDNSService(dnss_);
server.setXfrinSession(&notify_session);
......@@ -85,6 +87,8 @@ protected:
AuthSrv server;
const RRClass rrclass;
vector<uint8_t> response_data;
AddressList address_store_;
TestSocketRequestor sock_requestor_;
};
// A helper function that builds a response to version.bind/TXT/CH that
......@@ -887,6 +891,20 @@ TEST_F(AuthSrvTest, stop) {
TEST_F(AuthSrvTest, listenAddresses) {
isc::testutils::portconfig::listenAddresses(server);
// Check it requests the correct addresses
const char* tokens[] = {
"TCP:127.0.0.1:53210:1",
"UDP:127.0.0.1:53210:2",
"TCP:::1:53210:3",
"UDP:::1:53210:4",
NULL
};
sock_requestor_.checkTokens(tokens, sock_requestor_.given_tokens_,
"Given tokens");
// It returns back to empty set of addresses afterwards, so
// they should be released
sock_requestor_.checkTokens(tokens, sock_requestor_.released_tokens_,
"Released tokens");
}
}
......@@ -31,6 +31,7 @@
#include <testutils/mockups.h>
#include <testutils/portconfig.h>
#include <testutils/socket_request.h>
using namespace isc::dns;
using namespace isc::data;
......@@ -44,7 +45,8 @@ protected:
AuthConfigTest() :
dnss_(ios_, NULL, NULL, NULL),
rrclass(RRClass::IN()),
server(true, xfrout)
server(true, xfrout),
sock_requestor_(dnss_, address_store_, 53210)
{
server.setDNSService(dnss_);
}
......@@ -53,6 +55,9 @@ protected:
const RRClass rrclass;
MockXfroutClient xfrout;
AuthSrv server;
isc::server_common::portconfig::AddressList address_store_;
private:
isc::testutils::TestSocketRequestor sock_requestor_;
};
TEST_F(AuthConfigTest, datasourceConfig) {
......
......@@ -41,6 +41,8 @@
#include <cc/data.h>
#include <config/ccsession.h>
#include <server_common/socket_request.h>
#include <xfr/xfrout_client.h>
#include <auth/change_user.h>
......@@ -209,6 +211,7 @@ main(int argc, char* argv[]) {
config_session = new ModuleCCSession(specfile, *cc_session,
my_config_handler,
my_command_handler);
isc::server_common::SocketRequestor::init(*config_session);
LOG_DEBUG(resolver_logger, RESOLVER_DBG_INIT, RESOLVER_CONFIG_CHANNEL);
// FIXME: This does not belong here, but inside Boss
......
......@@ -49,6 +49,7 @@
#include <dns/tests/unittest_util.h>
#include <testutils/srv_test.h>
#include <testutils/portconfig.h>
#include <testutils/socket_request.h>
using namespace std;
using boost::scoped_ptr;
......@@ -81,7 +82,10 @@ protected:
scoped_ptr<const IOMessage> query_message;
scoped_ptr<const Client> client;
scoped_ptr<const RequestContext> request;
ResolverConfig() : dnss(ios, NULL, NULL, NULL) {
ResolverConfig() :
dnss(ios, NULL, NULL, NULL),
sock_requestor_(dnss, address_store_, 53210)
{
server.setDNSService(dnss);
}
const RequestContext& createRequest(const string& source_addr) {
......@@ -96,6 +100,8 @@ protected:
return (*request);
}
void invalidTest(const string &JSON, const string& name);
isc::server_common::portconfig::AddressList address_store_;
isc::testutils::TestSocketRequestor sock_requestor_;
};
TEST_F(ResolverConfig, forwardAddresses) {
......@@ -310,6 +316,20 @@ TEST_F(ResolverConfig, invalidForwardAddresses) {
// Try setting the addresses directly
TEST_F(ResolverConfig, listenAddresses) {
isc::testutils::portconfig::listenAddresses(server);
// Check it requests the correct addresses
const char* tokens[] = {
"TCP:127.0.0.1:53210:1",
"UDP:127.0.0.1:53210:2",
"TCP:::1:53210:3",
"UDP:::1:53210:4",
NULL
};
sock_requestor_.checkTokens(tokens, sock_requestor_.given_tokens_,
"Given tokens");
// It returns back to empty set of addresses afterwards, so
// they should be released
sock_requestor_.checkTokens(tokens, sock_requestor_.released_tokens_,
"Released tokens");
}
// Try setting some addresses and a rollback
......
......@@ -25,6 +25,7 @@ libasiodns_la_SOURCES += dns_service.cc dns_service.h
libasiodns_la_SOURCES += tcp_server.cc tcp_server.h
libasiodns_la_SOURCES += udp_server.cc udp_server.h
libasiodns_la_SOURCES += io_fetch.cc io_fetch.h
libasiodns_la_SOURCES += logger.h logger.cc
nodist_libasiodns_la_SOURCES = asiodns_messages.cc asiodns_messages.h
......
......@@ -14,6 +14,14 @@
$NAMESPACE isc::asiodns
% ASIODNS_FD_ADD_TCP adding a new TCP server by opened fd %1
A debug message informing about installing a file descriptor as a server.
The file descriptor number is noted.
% ASIODNS_FD_ADD_UDP adding a new UDP server by opened fd %1
A debug message informing about installing a file descriptor as a server.
The file descriptor number is noted.
% ASIODNS_FETCH_COMPLETED upstream fetch to %1(%2) has now completed
A debug message, this records that the upstream fetch (a query made by the
resolver on behalf of its client) to the specified address has completed.
......
......@@ -78,6 +78,13 @@ public:
DNSLookup *lookup_;
DNSAnswer *answer_;
template<class Ptr, class Server> void addServerFromFD(int fd, int af) {
Ptr server(new Server(io_service_.get_io_service(), fd, af, checkin_,
lookup_, answer_));
(*server)();
servers_.push_back(server);
}
void addServer(uint16_t port, const asio::ip::address& address) {
try {
dlog(std::string("Initialize TCP server at ") + address.to_string() + ":" + boost::lexical_cast<std::string>(port));
......@@ -189,6 +196,14 @@ DNSService::addServer(uint16_t port, const std::string& address) {
impl_->addServer(port, convertAddr(address));
}
void DNSService::addServerTCPFromFD(int fd, int af) {
impl_->addServerFromFD<DNSServiceImpl::TCPServerPtr, TCPServer>(fd, af);
}
void DNSService::addServerUDPFromFD(int fd, int af) {
impl_->addServerFromFD<DNSServiceImpl::UDPServerPtr, UDPServer>(fd, af);
}
void
DNSService::clearServers() {
BOOST_FOREACH(const DNSServiceImpl::DNSServerPtr& s, impl_->servers_) {
......
......@@ -88,6 +88,42 @@ public:
/// \brief Add another server to the service
void addServer(uint16_t port, const std::string &address);
void addServer(const char &port, const std::string &address);
/// \brief Add another TCP server/listener to the service from already
/// opened file descriptor
///
/// Adds a new TCP server using an already opened file descriptor (eg. it
/// only wraps it so the file descriptor is usable within the event loop).
/// The file descriptor must be associated with a TCP socket of the given
/// address family that is bound to an appropriate port (and possibly a
/// specific address) and is ready for listening to new connection
/// requests but has not actually started listening.
///
/// \param fd the file descriptor to be used.
/// \param af the address family of the file descriptor. Must be either
/// AF_INET or AF_INET6.
/// \throw isc::InvalidParameter if af is neither AF_INET nor AF_INET6.
/// \throw isc::asiolink::IOError when a low-level error happens, like the
/// fd is not a valid descriptor or it can't be listened on.
void addServerTCPFromFD(int fd, int af);
/// \brief Add another UDP server to the service from already opened
/// file descriptor
///
/// Adds a new UDP server using an already opened file descriptor (eg. it
/// only wraps it so the file descriptor is usable within the event loop).
/// The file descriptor must be associated with a UDP socket of the given
/// address family that is bound to an appropriate port (and possibly a
/// specific address).
///
/// \param fd the file descriptor to be used.
/// \param af the address family of the file descriptor. Must be either
/// AF_INET or AF_INET6.
/// \throw isc::InvalidParameter if af is neither AF_INET nor AF_INET6.
/// \throw isc::asiolink::IOError when a low-level error happens, like the
/// fd is not a valid descriptor or it can't be listened on.
void addServerUDPFromFD(int fd, int af);
/// \brief Remove all servers from the service
void clearServers();
......
......@@ -38,15 +38,13 @@
#include <dns/messagerenderer.h>
#include <dns/opcode.h>
#include <dns/rcode.h>
#include <log/logger.h>
#include <log/macros.h>
#include <asiodns/asiodns_messages.h>
#include <asiodns/io_fetch.h>
#include <util/buffer.h>
#include <util/random/qid_gen.h>
#include <asiodns/logger.h>
using namespace asio;
using namespace isc::asiolink;
......@@ -59,10 +57,6 @@ using namespace std;
namespace isc {
namespace asiodns {
/// Use the ASIO logger
isc::log::Logger logger("asiolink");
// Log debug verbosity
const int DBG_IMPORTANT = DBGLVL_TRACE_BASIC;
......
// Copyright (C) 2012 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.
#include <asiodns/logger.h>
namespace isc {
namespace asiodns {
/// Use the ASIO logger
isc::log::Logger logger("asiodns");
}
}
// Copyright (C) 2012 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.
#include <log/logger.h>
#include <log/macros.h>
#include <log/log_dbglevels.h>
#include <asiodns/asiodns_messages.h>
namespace isc {
namespace asiodns {
extern isc::log::Logger logger;
}
}
......@@ -29,8 +29,8 @@
#include <asiolink/dummy_io_cb.h>
#include <asiolink/tcp_endpoint.h>
#include <asiolink/tcp_socket.h>
#include <tcp_server.h>
#include <asiodns/tcp_server.h>
#include <asiodns/logger.h>
using namespace asio;
using asio::ip::udp;
......@@ -69,6 +69,31 @@ TCPServer::TCPServer(io_service& io_service,
acceptor_->listen();
}
TCPServer::TCPServer(io_service& io_service, int fd, int af,
const SimpleCallback* checkin,
const DNSLookup* lookup,
const DNSAnswer* answer) :
io_(io_service), done_(false),
checkin_callback_(checkin), lookup_callback_(lookup),
answer_callback_(answer)
{
if (af != AF_INET && af != AF_INET6) {
isc_throw(InvalidParameter, "Address family must be either AF_INET "
"or AF_INET6, not " << af);
}
LOG_DEBUG(logger, DBGLVL_TRACE_BASIC, ASIODNS_FD_ADD_TCP).arg(fd);
try {
acceptor_.reset(new tcp::acceptor(io_service));
acceptor_->assign(af == AF_INET6 ? tcp::v6() : tcp::v4(), fd);
acceptor_->listen();
} catch (const std::exception& exception) {
// Whatever the thing throws, it is something from ASIO and we convert
// it
isc_throw(IOError, exception.what());
}
}
void
TCPServer::operator()(asio::error_code ec, size_t length) {
/// Because the coroutine reentry block is implemented as
......
......@@ -43,6 +43,20 @@ public:
const DNSLookup* lookup = NULL,
const DNSAnswer* answer = NULL);
/// \brief Constructor
/// \param io_service the asio::io_service to work with
/// \param fd the file descriptor of opened TCP socket
/// \param af address family of the socket, either AF_INET or AF_INET6
/// \param checkin the callbackprovider for non-DNS events
/// \param lookup the callbackprovider for DNS lookup events
/// \param answer the callbackprovider for DNS answer events
/// \throw isc::InvalidParameter if af is neither AF_INET nor AF_INET6
/// \throw isc::asiolink::IOError when a low-level error happens, like the
/// fd is not a valid descriptor or it can't be listened on.
TCPServer(asio::io_service& io_service, int fd, int af,
const isc::asiolink::SimpleCallback* checkin = NULL,
const DNSLookup* lookup = NULL, const DNSAnswer* answer = NULL);
void operator()(asio::error_code ec = asio::error_code(),
size_t length = 0);
void asyncLookup();
......
......@@ -29,6 +29,7 @@
#include <asiolink/udp_endpoint.h>
#include <asiolink/udp_socket.h>
#include "udp_server.h"
#include "logger.h"
#include <dns/opcode.h>
......@@ -53,7 +54,7 @@ namespace asiodns {
*/
struct UDPServer::Data {
/*
* Constructor from parameters passed to UDPServer constructor.
* Constructors from parameters passed to UDPServer constructor.
* This instance will not be used to retrieve and answer the actual
* query, it will only hold parameters until we wait for the
* first packet. But we do initialize the socket in here.
......@@ -74,6 +75,26 @@ struct UDPServer::Data {
}
socket_->bind(udp::endpoint(addr, port));
}
Data(io_service& io_service, int fd, int af, SimpleCallback* checkin,
DNSLookup* lookup, DNSAnswer* answer) :
io_(io_service), done_(false),
checkin_callback_(checkin),lookup_callback_(lookup),
answer_callback_(answer)
{
if (af != AF_INET && af != AF_INET6) {
isc_throw(InvalidParameter, "Address family must be either AF_INET "
"or AF_INET6, not " << af);
}
LOG_DEBUG(logger, DBGLVL_TRACE_BASIC, ASIODNS_FD_ADD_UDP).arg(fd);
try {
socket_.reset(new udp::socket(io_service));
socket_->assign(af == AF_INET6 ? udp::v6() : udp::v4(), fd);
} catch (const std::exception& exception) {
// Whatever the thing throws, it is something from ASIO and we
// convert it
isc_throw(IOError, exception.what());
}
}
/*
* Copy constructor. Default one would probably do, but it is unnecessary
......@@ -162,11 +183,17 @@ struct UDPServer::Data {
/// The constructor. It just creates new internal state object
/// and lets it handle the initialization.
UDPServer::UDPServer(io_service& io_service, const ip::address& addr,
const uint16_t port, SimpleCallback* checkin, DNSLookup* lookup,
DNSAnswer* answer) :
const uint16_t port, SimpleCallback* checkin,
DNSLookup* lookup, DNSAnswer* answer) :
data_(new Data(io_service, addr, port, checkin, lookup, answer))
{ }
UDPServer::UDPServer(io_service& io_service, int fd, int af,
SimpleCallback* checkin, DNSLookup* lookup,
DNSAnswer* answer) :
data_(new Data(io_service, fd, af, checkin, lookup, answer))
{ }
/// The function operator is implemented with the "stackless coroutine"
/// pattern; see internal/coroutine.h for details.
void
......
......@@ -52,6 +52,20 @@ public:
DNSLookup* lookup = NULL,
DNSAnswer* answer = NULL);
/// \brief Constructor
/// \param io_service the asio::io_service to work with
/// \param fd the file descriptor of opened UDP socket
/// \param af address family, either AF_INET or AF_INET6
/// \param checkin the callbackprovider for non-DNS events
/// \param lookup the callbackprovider for DNS lookup events
/// \param answer the callbackprovider for DNS answer events
/// \throw isc::InvalidParameter if af is neither AF_INET nor AF_INET6
/// \throw isc::asiolink::IOError when a low-level error happens, like the
/// fd is not a valid descriptor.
UDPServer(asio::io_service& io_service, int fd, int af,
isc::asiolink::SimpleCallback* checkin = NULL,
DNSLookup* lookup = NULL, DNSAnswer* answer = NULL);
/// \brief The function operator
void operator()(asio::error_code ec = asio::error_code(),
size_t length = 0);
......
......@@ -21,6 +21,7 @@ libserver_common_la_SOURCES = client.h client.cc
libserver_common_la_SOURCES += keyring.h keyring.cc
libserver_common_la_SOURCES += portconfig.h portconfig.cc
libserver_common_la_SOURCES += logger.h logger.cc
libserver_common_la_SOURCES += socket_request.h socket_request.cc
nodist_libserver_common_la_SOURCES = server_common_messages.h
nodist_libserver_common_la_SOURCES += server_common_messages.cc
libserver_common_la_LIBADD = $(top_builddir)/src/lib/exceptions/libexceptions.la
......
......@@ -14,6 +14,7 @@
#include <server_common/portconfig.h>
#include <server_common/logger.h>
#include <server_common/socket_request.h>
#include <asiolink/io_address.h>
#include <asiodns/dns_service.h>
......@@ -30,6 +31,11 @@ namespace isc {
namespace server_common {
namespace portconfig {
// This flags disables pushing the sockets to the DNSService. It prevents
// the clearServers() method to close the file descriptors we made up.
// It is not presented in any header, but we use it from the tests anyway.
bool test_mode(false);
AddressList
parseAddresses(isc::data::ConstElementPtr addresses,
const std::string& elemName)
......@@ -76,11 +82,41 @@ parseAddresses(isc::data::ConstElementPtr addresses,
namespace {
vector<string> current_sockets;
void
setAddresses(DNSService& service, const AddressList& addresses) {
service.clearServers();
BOOST_FOREACH(const string& token, current_sockets) {
socketRequestor().releaseSocket(token);
}
current_sockets.clear();
BOOST_FOREACH(const AddressPair &address, addresses) {
service.addServer(address.second, address.first);
const int af(IOAddress(address.first).getFamily());
// TODO: Support sharing somehow in future.
// As for now, we hardcode the application name as dummy_app, because:
// * we don't have a name available in our interface, which will change
// soon anyway
// * we use the DONT_SHARE mode, so the name is irrelevant anyway
const SocketRequestor::SocketID
tcp(socketRequestor().requestSocket(SocketRequestor::TCP,
address.first, address.second,
SocketRequestor::DONT_SHARE,
"dummy_app"));
current_sockets.push_back(tcp.second);
if (!test_mode) {
service.addServerTCPFromFD(tcp.first, af);
}
const SocketRequestor::SocketID
udp(socketRequestor().requestSocket(SocketRequestor::UDP,
address.first, address.second,
SocketRequestor::DONT_SHARE,
"dummy_app"));
current_sockets.push_back(udp.second);
if (!test_mode) {
service.addServerUDPFromFD(udp.first, af);
}
}
}
......@@ -117,9 +153,13 @@ installListenAddresses(const AddressList& newAddresses,
LOG_ERROR(logger, SRVCOMM_ADDRESS_FAIL).arg(e.what());
try {
setAddresses(service, addressStore);
}
catch (const exception& e2) {
} catch (const exception& e2) {
LOG_FATAL(logger, SRVCOMM_ADDRESS_UNRECOVERABLE).arg(e2.what());
// If we can't set the new ones, nor the old ones, at least
// releasing everything should work. If it doesn't, there isn't
// anything else we could do.
setAddresses(service, AddressList());
addressStore.clear();
}
//Anyway the new configure has problem, we need to notify configure
//manager the new configure doesn't work
......
......@@ -96,10 +96,12 @@ parseAddresses(isc::data::ConstElementPtr addresses,
*
* If it fails to set up the new addresses, it attempts to roll back to the
* previous addresses (but it still propagates the exception). If the rollback
* fails as well, it aborts the application (it assumes if it can't listen
* on the new addresses nor on the old ones, the application is useless anyway
* and should be restarted by Boss, not to mention that the internal state is
* probably broken).
* fails as well, it doesn't abort the application (to allow reconfiguration),
* but removes all the sockets it listened on. One of the exceptions is
* propagated.
*
* The ports are requested from the socket creator through boss. Therefore
* you need to initialize the SocketRequestor before using this function.
*
* \param newAddresses are the addresses you want to listen on.
* \param addressStore is the place you store your current addresses. It is
......@@ -109,7 +111,11 @@ parseAddresses(isc::data::ConstElementPtr addresses,
* the new sockets are handled using this dnsService (and all current
* sockets on the service are closed first).
* \throw asiolink::IOError when initialization or closing of socket fails.
* \throw isc::server_common::SocketRequestor::Socket error when the
* boss/socket creator doesn't want to give us the socket.
* \throw std::bad_alloc when allocation fails.
* \throw isc::InvalidOperation when the function is called and the
* SocketRequestor isn't initialized yet.
*/
void
installListenAddresses(const AddressList& newAddresses,
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment