Commit 71be4dc1 authored by Michal 'vorner' Vaner's avatar Michal 'vorner' Vaner
Browse files
parents 673bbeb9 fc4e4e5c
bind10-1.0.0beta2 released on May 3, 2013
610. [bug] muks
When the sqlite3 program is not available on the system (in
PATH), we no longer attempt to run some tests which depend
on it.
(Trac #1909, git f85b274b85b57a094d33ca06dfbe12ae67bb47df)
609. [bug] jinmei
Handled some rare error cases in DNS server classes correctly.
This fix specifically solves occasional crash of b10-auth due to
errors caused by TCP DNS clients. Also, as a result of cleanups
with the fix, b10-auth should now be a little bit faster in
handling UDP queries: in some local experiments it ran about 5%
faster.
(Trac #2903, git 6d3e0f4b36a754248f8a03a29e2c36aef644cdcc)
608. [bug] jinmei
b10-cmdctl: fixed a hangup problem on receiving the shutdown
command from bindctl. Note, however, that cmdctl is defined as
......@@ -52,7 +69,7 @@
(Trac #2770, git a622140d411b3f07a68a1451e19df36118a80650)
602. [bug] tmark
Perdhcp will now exit gracefully if the command line argument for
Perfdhcp will now exit gracefully if the command line argument for
IP version (-4 or -6) does not match the command line argument
given for the server. Prior to this perfdhcp would core when given
an IP version of -6 but a valid IPv4 address for server.
......
......@@ -2,7 +2,7 @@ ACLOCAL_AMFLAGS = -I m4macros -I examples/m4 ${ACLOCAL_FLAGS}
# ^^^^^^^^ This has to be the first line and cannot come later in this
# Makefile.am due to some bork in some versions of autotools.
SUBDIRS = compatcheck doc . src tests
SUBDIRS = compatcheck doc . src tests m4macros
USE_LCOV=@USE_LCOV@
LCOV=@LCOV@
GENHTML=@GENHTML@
......@@ -46,7 +46,7 @@ endif
clean-cpp-coverage:
@if [ $(USE_LCOV) = yes ] ; then \
$(LCOV) --directory . --zerocounters; \
rm -rf coverage/; \
rm -rf $(abs_top_srcdir)/coverage-cpp-html/; \
else \
echo "C++ code coverage not enabled at configuration time." ; \
echo "Use: ./configure --with-lcov" ; \
......
......@@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.59])
AC_INIT(bind10, 20130221, bind10-dev@isc.org)
AC_INIT(bind10, 20130503, bind10-dev@isc.org)
AC_CONFIG_SRCDIR(README)
# serial-tests is not available in automake version before 1.13. In
# automake 1.13 and higher, AM_PROG_INSTALL is undefined, so we'll check
......@@ -388,8 +388,6 @@ In this case we will continue, but naming of python processes will not work.])
fi
fi
# TODO: check for _sqlite3.py module
# (g++ only check)
# Python 3.2 has an unused parameter in one of its headers. This
# has been reported, but not fixed as of yet, so we check if we need
......@@ -1043,12 +1041,16 @@ AC_SUBST(GTEST_LDFLAGS)
AC_SUBST(GTEST_LDADD)
AC_SUBST(GTEST_SOURCE)
dnl check for pkg-config itself so we don't try the m4 macro without pkg-config
dnl check for pkg-config itself
AC_CHECK_PROG(HAVE_PKG_CONFIG, pkg-config, yes, no)
if test "x$HAVE_PKG_CONFIG" = "xno" ; then
AC_MSG_ERROR(Please install pkg-config)
fi
PKG_CHECK_MODULES(SQLITE, sqlite3 >= 3.3.9, enable_features="$enable_features SQLite3")
AX_SQLITE3_FOR_BIND10
if test "x$have_sqlite" = "xyes" ; then
enable_features="$enable_features SQLite3"
fi
#
# ASIO: we extensively use it as the C++ event management module.
......@@ -1323,6 +1325,7 @@ AC_CONFIG_FILES([Makefile
tests/tools/perfdhcp/Makefile
tests/tools/perfdhcp/tests/Makefile
tests/tools/perfdhcp/tests/testdata/Makefile
m4macros/Makefile
dns++.pc
])
AC_OUTPUT([doc/version.ent
......
EXTRA_DIST = ax_boost_for_bind10.m4
EXTRA_DIST += ax_sqlite3_for_bind10.m4
dnl @synopsis AX_SQLITE3_FOR_BIND10
dnl
dnl Test for the sqlite3 library and program, intended to be used within
dnl BIND 10, and to test BIND 10.
dnl
dnl We use pkg-config to look for the sqlite3 library, so the sqlite3
dnl development package with the .pc file must be installed.
dnl
dnl This macro sets SQLITE_CFLAGS and SQLITE_LIBS. It also sets
dnl SQLITE3_PROGRAM to the path of the sqlite3 program, if it is found
dnl in PATH.
AC_DEFUN([AX_SQLITE3_FOR_BIND10], [
PKG_CHECK_MODULES(SQLITE, sqlite3 >= 3.3.9,
have_sqlite="yes",
have_sqlite="no (sqlite3 not detected)")
# Check for sqlite3 program
AC_PATH_PROG(SQLITE3_PROGRAM, sqlite3, no)
AM_CONDITIONAL(HAVE_SQLITE3_PROGRAM, test "x$SQLITE3_PROGRAM" != "xno")
# TODO: check for _sqlite3.py module
])dnl AX_SQLITE3_FOR_BIND10
......@@ -5,5 +5,11 @@ SUBDIRS = . testdata
noinst_SCRIPTS = dbutil_test.sh
check-local:
if HAVE_SQLITE3_PROGRAM
B10_LOCKFILE_DIR_FROM_BUILD=$(abs_top_builddir) \
$(SHELL) $(abs_builddir)/dbutil_test.sh
else
@echo ""
@echo " **** The sqlite3 program is required to run dbutil tests **** "
@echo ""
endif
......@@ -53,6 +53,78 @@ The asynchronous I/O code encountered an error when trying to send data to
the specified address on the given protocol. The number of the system
error that caused the problem is given in the message.
% ASIODNS_SYNC_UDP_CLOSE_FAIL failed to close a DNS/UDP socket: %1
This is the same to ASIODNS_UDP_CLOSE_FAIL but happens on the
"synchronous UDP server", mainly used for the authoritative DNS server
daemon.
% ASIODNS_TCP_ACCEPT_FAIL failed to accept TCP DNS connection: %1
Accepting a TCP connection from a DNS client failed due to an error
that could happen but should be rare. The reason for the error is
included in the log message. The server still keeps accepting new
connections, so unless it happens often it's probably okay to ignore
this error. If the shown error indicates something like "too many
open files", it's probably because the run time environment is too
restrictive on this limitation, so consider adjusing the limit using
a tool such as ulimit. If you see other types of errors too often,
there may be something overlooked; please file a bug report in that case.
% ASIODNS_TCP_CLEANUP_CLOSE_FAIL failed to close a DNS/TCP socket on port cleanup: %1
A TCP DNS server tried to close a TCP socket (one created on accepting
a new connection or is already unused) as a step of cleaning up the
corresponding listening port, but it failed to do that. This is
generally an unexpected event and so is logged as an error.
See also the description of ASIODNS_TCP_CLOSE_ACCEPTOR_FAIL.
% ASIODNS_TCP_CLOSE_ACCEPTOR_FAIL failed to close listening TCP socket: %1
A TCP DNS server tried to close a listening TCP socket (for accepting
new connections) as a step of cleaning up the corresponding listening
port (e.g., on server shutdown or updating port configuration), but it
failed to do that. This is generally an unexpected event and so is
logged as an error. See ASIODNS_TCP_CLOSE_FAIL on the implication of
related system resources.
% ASIODNS_TCP_CLOSE_FAIL failed to close DNS/TCP socket with a client: %1
A TCP DNS server tried to close a TCP socket used to communicate with
a client, but it failed to do that. While closing a socket should
normally be an error-free operation, there have been known cases where
this happened with a "connection reset by peer" error. This might be
because of some odd client behavior, such as sending a TCP RST after
establishing the connection and before the server closes the socket,
but how exactly this could happen seems to be system dependent (i.e,
it's not part of the standard socket API), so it's difficult to
provide a general explanation. In any case, it is believed that an
error on closing a socket doesn't mean leaking system resources (the
kernel should clean up any internal resource related to the socket,
just reporting an error detected in the close call), but, again, it
seems to be system dependent. This message is logged at a debug level
as it's known to happen and could be triggered by a remote node and it
would be better to not be too verbose, but you might want to increase
the log level and make sure there's no resource leak or other system
level troubles when it's logged.
% ASIODNS_TCP_GETREMOTE_FAIL failed to get remote address of a DNS TCP connection: %1
A TCP DNS server tried to get the address and port of a remote client
on a connected socket but failed. It's expected to be rare but can
still happen. See also ASIODNS_TCP_READLEN_FAIL.
% ASIODNS_TCP_READDATA_FAIL failed to get DNS data on a TCP socket: %1
A TCP DNS server tried to read a DNS message (that follows a 2-byte
length field) but failed. It's expected to be rare but can still happen.
See also ASIODNS_TCP_READLEN_FAIL.
% ASIODNS_TCP_READLEN_FAIL failed to get DNS data length on a TCP socket: %1
A TCP DNS server tried to get the length field of a DNS message (the first
2 bytes of a new chunk of data) but failed. This is generally expected to
be rare but can still happen, e.g, due to an unexpected reset of the
connection. A specific reason for the failure is included in the log
message.
% ASIODNS_TCP_WRITE_FAIL failed to send DNS message over a TCP socket: %1
A TCP DNS server tried to send a DNS message to a remote client but
failed. It's expected to be rare but can still happen. See also
ASIODNS_TCP_READLEN_FAIL.
% ASIODNS_UDP_ASYNC_SEND_FAIL Error sending UDP packet to %1: %2
The low-level ASIO library reported an error when trying to send a UDP
packet in asynchronous UDP mode. This can be any error reported by
......@@ -64,6 +136,23 @@ If you see a single occurrence of this message, it probably does not
indicate any significant problem, but if it is logged often, it is probably
a good idea to inspect your network traffic.
% ASIODNS_UDP_CLOSE_FAIL failed to close a DNS/UDP socket: %1
A UDP DNS server tried to close its UDP socket, but failed to do that.
This is generally an unexpected event and so is logged as an error.
% ASIODNS_UDP_RECEIVE_FAIL failed to receive UDP DNS packet: %1
Receiving a UDP packet from a DNS client failed due to an error that
could happen but should be very rare. The server still keeps
receiving UDP packets on this socket. The reason for the error is
included in the log message. This log message is basically not
expected to appear at all in practice; if it does, there may be some
system level failure and other system logs may have to be checked.
% ASIODNS_UDP_SYNC_RECEIVE_FAIL failed to receive UDP DNS packet: %1
This is the same to ASIODNS_UDP_RECEIVE_FAIL but happens on the
"synchronous UDP server", mainly used for the authoritative DNS server
daemon.
% ASIODNS_UDP_SYNC_SEND_FAIL Error sending UDP packet to %1: %2
The low-level ASIO library reported an error when trying to send a UDP
packet in synchronous UDP mode. See ASIODNS_UDP_ASYNC_SEND_FAIL for
......
......@@ -58,9 +58,15 @@ public:
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->setTCPRecvTimeout(tcp_recv_timeout_);
(*server)();
servers_.push_back(server);
startServer(server);
}
// SyncUDPServer has different constructor signature so it cannot be
// templated.
void addSyncUDPServerFromFD(int fd, int af) {
SyncUDPServerPtr server(new SyncUDPServer(io_service_.get_io_service(),
fd, af, lookup_));
startServer(server);
}
void setTCPRecvTimeout(size_t timeout) {
......@@ -72,6 +78,13 @@ public:
(*it)->setTCPRecvTimeout(timeout);
}
}
private:
void startServer(DNSServerPtr server) {
server->setTCPRecvTimeout(tcp_recv_timeout_);
(*server)();
servers_.push_back(server);
}
};
DNSService::DNSService(IOService& io_service, SimpleCallback* checkin,
......@@ -95,8 +108,7 @@ void DNSService::addServerUDPFromFD(int fd, int af, ServerFlag options) {
<< options);
}
if ((options & SERVER_SYNC_OK) != 0) {
impl_->addServerFromFD<DNSServiceImpl::SyncUDPServerPtr,
SyncUDPServer>(fd, af);
impl_->addSyncUDPServerFromFD(fd, af);
} else {
impl_->addServerFromFD<DNSServiceImpl::UDPServerPtr, UDPServer>(
fd, af);
......
......@@ -39,18 +39,21 @@ namespace isc {
namespace asiodns {
SyncUDPServer::SyncUDPServer(asio::io_service& io_service, const int fd,
const int af, asiolink::SimpleCallback* checkin,
DNSLookup* lookup, DNSAnswer* answer) :
const int af, DNSLookup* lookup) :
output_buffer_(new isc::util::OutputBuffer(0)),
query_(new isc::dns::Message(isc::dns::Message::PARSE)),
answer_(new isc::dns::Message(isc::dns::Message::RENDER)),
checkin_callback_(checkin), lookup_callback_(lookup),
answer_callback_(answer), stopped_(false)
udp_endpoint_(sender_), lookup_callback_(lookup),
resume_called_(false), done_(false), stopped_(false),
recv_callback_(boost::bind(&SyncUDPServer::handleRead, this, _1, _2))
{
if (af != AF_INET && af != AF_INET6) {
isc_throw(InvalidParameter, "Address family must be either AF_INET "
"or AF_INET6, not " << af);
}
if (!lookup) {
isc_throw(InvalidParameter, "null lookup callback given to "
"SyncUDPServer");
}
LOG_DEBUG(logger, DBGLVL_TRACE_BASIC, ASIODNS_FD_ADD_UDP).arg(fd);
try {
socket_.reset(new asio::ip::udp::socket(io_service));
......@@ -61,59 +64,36 @@ SyncUDPServer::SyncUDPServer(asio::io_service& io_service, const int fd,
// convert it
isc_throw(IOError, exception.what());
}
udp_socket_.reset(new UDPSocket<DummyIOCallback>(*socket_));
}
void
SyncUDPServer::scheduleRead() {
socket_->async_receive_from(asio::buffer(data_, MAX_LENGTH), sender_,
boost::bind(&SyncUDPServer::handleRead, this,
_1, _2));
socket_->async_receive_from(asio::mutable_buffers_1(data_, MAX_LENGTH),
sender_, recv_callback_);
}
void
SyncUDPServer::handleRead(const asio::error_code& ec, const size_t length) {
// Abort on fatal errors
if (ec) {
using namespace asio::error;
if (ec.value() != would_block && ec.value() != try_again &&
ec.value() != interrupted) {
const asio::error_code::value_type err_val = ec.value();
// See TCPServer::operator() for details on error handling.
if (err_val == operation_aborted || err_val == bad_descriptor) {
return;
}
if (err_val != would_block && err_val != try_again &&
err_val != interrupted) {
LOG_ERROR(logger, ASIODNS_UDP_SYNC_RECEIVE_FAIL).arg(ec.message());
}
}
// Some kind of interrupt, spurious wakeup, or like that. Just try reading
// again.
if (ec || length == 0) {
scheduleRead();
return;
}
// OK, we have a real packet of data. Let's dig into it!
// XXX: This is taken (and ported) from UDPSocket class. What the hell does
// it really mean?
// The UDP socket class has been extended with asynchronous functions
// and takes as a template parameter a completion callback class. As
// UDPServer does not use these extended functions (only those defined
// in the IOSocket base class) - but needs a UDPSocket to get hold of
// the underlying Boost UDP socket - DummyIOCallback is used. This
// provides the appropriate operator() but is otherwise functionless.
UDPSocket<DummyIOCallback> socket(*socket_);
UDPEndpoint endpoint(sender_);
IOMessage message(data_, length, socket, endpoint);
if (checkin_callback_ != NULL) {
(*checkin_callback_)(message);
if (stopped_) {
return;
}
}
// If we don't have a DNS Lookup provider, there's no point in
// continuing; we exit the coroutine permanently.
if (lookup_callback_ == NULL) {
scheduleRead();
return;
}
// Make sure the buffers are fresh. Note that we don't touch query_
// because it's supposed to be cleared in lookup_callback_. We should
// eventually even remove this member variable (and remove it from
......@@ -121,13 +101,13 @@ SyncUDPServer::handleRead(const asio::error_code& ec, const size_t length) {
// implementation should be careful that it's the responsibility of
// the callback implementation. See also #2239).
output_buffer_->clear();
answer_->clear(isc::dns::Message::RENDER);
// Mark that we don't have an answer yet.
done_ = false;
resume_called_ = false;
// Call the actual lookup
const IOMessage message(data_, length, *udp_socket_, udp_endpoint_);
(*lookup_callback_)(message, query_, answer_, output_buffer_, this);
if (!resume_called_) {
......@@ -135,27 +115,14 @@ SyncUDPServer::handleRead(const asio::error_code& ec, const size_t length) {
"No resume called from the lookup callback");
}
if (stopped_) {
return;
}
if (done_) {
// Good, there's an answer.
// Call the answer callback to render it.
(*answer_callback_)(message, query_, answer_, output_buffer_);
if (stopped_) {
return;
}
asio::error_code ec;
socket_->send_to(asio::buffer(output_buffer_->getData(),
output_buffer_->getLength()),
sender_, 0, ec);
if (ec) {
socket_->send_to(asio::const_buffers_1(output_buffer_->getData(),
output_buffer_->getLength()),
sender_, 0, ec_);
if (ec_) {
LOG_ERROR(logger, ASIODNS_UDP_SYNC_SEND_FAIL).
arg(sender_.address().to_string()).
arg(ec.message());
arg(sender_.address().to_string()).arg(ec_.message());
}
}
......@@ -181,13 +148,13 @@ SyncUDPServer::stop() {
/// for it won't be scheduled by io service not matter it is
/// submit to io service before or after close call. And we will
/// get bad_descriptor error.
socket_->close();
socket_->close(ec_);
stopped_ = true;
if (ec_) {
LOG_ERROR(logger, ASIODNS_SYNC_UDP_CLOSE_FAIL).arg(ec_.message());
}
}
/// Post this coroutine on the ASIO service queue so that it will
/// resume processing where it left off. The 'done' parameter indicates
/// whether there is an answer to return to the client.
void
SyncUDPServer::resume(const bool done) {
resume_called_ = true;
......
......@@ -25,10 +25,14 @@
#include <dns/message.h>
#include <asiolink/simple_callback.h>
#include <asiolink/dummy_io_cb.h>
#include <asiolink/udp_socket.h>
#include <util/buffer.h>
#include <exceptions/exceptions.h>
#include <boost/function.hpp>
#include <boost/noncopyable.hpp>
#include <boost/scoped_ptr.hpp>
#include <stdint.h>
......@@ -39,29 +43,39 @@ namespace asiodns {
///
/// That means, the lookup handler must provide the answer right away.
/// This allows for implementation with less overhead, compared with
/// the UDPClass.
/// the \c UDPServer class.
class SyncUDPServer : public DNSServer, public boost::noncopyable {
public:
/// \brief Constructor
///
/// Due to the nature of this server, it's meaningless if the lookup
/// callback is NULL. So the constructor explicitly rejects that case
/// with an exception. Likewise, it doesn't take "checkin" or "answer"
/// callbacks. In fact, calling "checkin" from receive callback does not
/// make sense for any of the DNSServer variants (see Trac #2935);
/// "answer" callback is simply unnecessary for this class because a
/// complete answer is built in the lookup callback (it's the user's
/// responsibility to guarantee that condition).
///
/// \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
/// \param lookup the callbackprovider for DNS lookup events (must not be
/// NULL)
///
/// \throw isc::InvalidParameter if af is neither AF_INET nor AF_INET6
/// \throw isc::InvalidParameter lookup is NULL
/// \throw isc::asiolink::IOError when a low-level error happens, like the
/// fd is not a valid descriptor.
SyncUDPServer(asio::io_service& io_service, const int fd, const int af,
isc::asiolink::SimpleCallback* checkin = NULL,
DNSLookup* lookup = NULL, DNSAnswer* answer = NULL);
DNSLookup* lookup);
/// \brief Start the SyncUDPServer.
///
/// This is the function operator to keep interface with other server
/// classes. They need that because they're coroutines.
virtual void operator()(asio::error_code ec = asio::error_code(),
size_t length = 0);
size_t length = 0);
/// \brief Calls the lookup callback
virtual void asyncLookup() {
......@@ -114,22 +128,39 @@ private:
// If it was OK to have just a buffer, not the wrapper class,
// we could reuse the data_
isc::util::OutputBufferPtr output_buffer_;
// Objects to hold the query message and the answer
// Objects to hold the query message and the answer. The latter isn't
// used and only defined as a placeholder as the callback signature
// requires it.
isc::dns::MessagePtr query_, answer_;
// The socket used for the communication
std::auto_ptr<asio::ip::udp::socket> socket_;
// Wrapper of socket_ in the form of asiolink::IOSocket.
// "DummyIOCallback" is not necessary for this class, but using the
// template is the easiest way to create a UDP instance of IOSocket.
boost::scoped_ptr<asiolink::UDPSocket<asiolink::DummyIOCallback> >
udp_socket_;
// Place the socket puts the sender of a packet when it is received
asio::ip::udp::endpoint sender_;
// Callbacks
const asiolink::SimpleCallback* checkin_callback_;
// Wrapper of sender_ in the form of asiolink::IOEndpoint. It's set to
// refer to sender_ on initialization, and keeps the reference throughout
// this server class.
asiolink::UDPEndpoint udp_endpoint_;
// Callback
const DNSLookup* lookup_callback_;
const DNSAnswer* answer_callback_;
// Answers from the lookup callback (not sent directly, but signalled
// through resume()
bool resume_called_, done_;
// This turns true when the server stops. Allows for not sending the
// answer after we closed the socket.
bool stopped_;
// Placeholder for error code object. It will be passed to ASIO library
// to have it set in case of error.
asio::error_code ec_;
// The callback functor for internal asynchronous read event. This is
// stateless (and it will be copied in the ASIO library anyway), so
// can be const
const boost::function<void(const asio::error_code&, size_t)>
recv_callback_;
// Auxiliary functions
......@@ -144,3 +175,7 @@ private:
} // namespace asiodns
} // namespace isc
#endif // SYNC_UDP_SERVER_H
// Local Variables:
// mode: c++
// End:
......@@ -14,13 +14,6 @@
#include <config.h>
#include <unistd.h> // for some IPC/network system calls
#include <netinet/in.h>
#include <sys/socket.h>
#include <errno.h>
#include <boost/shared_array.hpp>
#include <log/dummylog.h>
#include <util/buffer.h>
......@@ -32,6 +25,14 @@
#include <asiodns/tcp_server.h>
#include <asiodns/logger.h>
#include <boost/shared_array.hpp>
#include <cassert>
#include <unistd.h> // for some IPC/network system calls
#include <netinet/in.h>
#include <sys/socket.h>
#include <errno.h>
using namespace asio;
using asio::ip::udp;
using asio::ip::tcp;
......@@ -100,41 +101,58 @@ TCPServer::operator()(asio::error_code ec, size_t length) {
CORO_REENTER (this) {
do {
/// Create a socket to listen for connections
/// Create a socket to listen for connections (no-throw operation)
socket_.reset(new tcp::socket(acceptor_->get_io_service()));
/// Wait for new connections. In the event of non-fatal error,
/// try again
do {
CORO_YIELD acceptor_->async_accept(*socket_, *this);
// Abort on fatal errors
// TODO: Log error?
if (ec) {
using namespace asio::error;
if (ec.value() != would_block && ec.value() != try_again &&
ec.value() != connection_aborted &&
ec.value() != interrupted) {
const error_code::value_type err_val = ec.value();
// The following two cases can happen when this server is
// stopped: operation_aborted in case it's stopped after
// starting accept(). bad_descriptor in case it's stopped
// even before starting. In these cases we should simply
// stop handling events.
if (err_val == operation_aborted ||
err_val == bad_descriptor) {
return;
}
// Other errors should generally be temporary and we should
// keep waiting for new connections. We log errors that
// should really be rare and would only be caused by an
// internal erroneous condition (not an odd remote
// behavior).
if (err_val != would_block && err_val != try_again &&
err_val != connection_aborted &&
err_val != interrupted) {
LOG_ERROR(logger, ASIODNS_TCP_ACCEPT_FAIL).
arg(ec.message());