Commit 50c35b27 authored by Thomas Markwalder's avatar Thomas Markwalder

[3089] D2UpdateMgr now uses NameChangeTransaction derivations

Now that NameAddTransaction and NameRemoveTransction classes
have been implemented, D2UpdateMgr has been updated to use
them.  It now creates instances of NameAddTransaction and
NameRemoveTransaction based on the change type specified in
received NameChangeRequests as designed.
parent e7cac9c4
......@@ -21,6 +21,8 @@
#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>
#include <string>
namespace isc {
namespace d2 {
......@@ -49,6 +51,20 @@ DnsServerInfo::DnsServerInfo(const std::string& hostname,
DnsServerInfo::~DnsServerInfo() {
}
std::string
DnsServerInfo::toText() const {
std::ostringstream stream;
stream << (getIpAddress().toText()) << " port:" << getPort();
return (stream.str());
}
std::ostream&
operator<<(std::ostream& os, const DnsServerInfo& server) {
os << server.toText();
return (os);
}
// *********************** DdnsDomain *************************
DdnsDomain::DdnsDomain(const std::string& name, const std::string& key_name,
......@@ -253,7 +269,7 @@ TSIGKeyInfoParser::commit() {
TSIGKeyInfoListParser::TSIGKeyInfoListParser(const std::string& list_name,
TSIGKeyInfoMapPtr keys)
:list_name_(list_name), keys_(keys), local_keys_(new TSIGKeyInfoMap()),
:list_name_(list_name), keys_(keys), local_keys_(new TSIGKeyInfoMap()),
parsers_() {
if (!keys_) {
isc_throw(D2CfgError, "TSIGKeyInfoListParser ctor:"
......@@ -291,9 +307,9 @@ TSIGKeyInfoListParser::commit() {
BOOST_FOREACH(isc::dhcp::ParserPtr parser, parsers_) {
parser->commit();
}
// Now that we know we have a valid list, commit that list to the
// area given to us during construction (i.e. to the d2 context).
// area given to us during construction (i.e. to the d2 context).
*keys_ = *local_keys_;
}
......
......@@ -288,6 +288,9 @@ public:
enabled_ = false;
}
/// @brief Returns a text representation for the server.
std::string toText() const;
private:
/// @brief The resolvable name of the server. If not blank, then the
......@@ -306,6 +309,9 @@ private:
bool enabled_;
};
std::ostream&
operator<<(std::ostream& os, const DnsServerInfo& server);
/// @brief Defines a pointer for DnsServerInfo instances.
typedef boost::shared_ptr<DnsServerInfo> DnsServerInfoPtr;
......
......@@ -438,3 +438,10 @@ This is an error message issued after DHCP_DDNS attempts to submit DNS mapping
entry removals have failed. The precise reason for the failure should be
documented in preceding log entries.
% DHCP_DDNS_UPDATE_REQUEST_SENT for transaction key: %1 to server : %2
This is a debug message issued when DHCP_DDNS sends a DNS request to a DNS
server.
% DHCP_DDNS_UPDATE_RESPONSE_RECEIVED for transaction key: %1 to server : %2 status: %3
This is a debug message issued when DHCP_DDNS receives sends a DNS update
response from a DNS server.
......@@ -13,6 +13,8 @@
// PERFORMANCE OF THIS SOFTWARE.
#include <d2/d2_update_mgr.h>
#include <d2/nc_add.h>
#include <d2/nc_remove.h>
#include <sstream>
#include <iostream>
......@@ -85,16 +87,12 @@ D2UpdateMgr::checkFinishedTransactions() {
TransactionList::iterator it = transaction_list_.begin();
while (it != transaction_list_.end()) {
NameChangeTransactionPtr trans = (*it).second;
switch (trans->getNcrStatus()) {
case dhcp_ddns::ST_COMPLETED:
if (trans->isModelDone()) {
// @todo Addtional actions based on NCR status could be
// performed here.
transaction_list_.erase(it++);
break;
case dhcp_ddns::ST_FAILED:
transaction_list_.erase(it++);
break;
default:
} else {
++it;
break;
}
}
}
......@@ -163,12 +161,24 @@ D2UpdateMgr::makeTransaction(dhcp_ddns::NameChangeRequestPtr& next_ncr) {
}
// We matched to the required servers, so construct the transaction.
NameChangeTransactionPtr trans(new NameChangeTransaction(io_service_,
next_ncr,
forward_domain,
reverse_domain));
// @todo If multi-threading is implemented, one would pass in an
// empty IOServicePtr, rather than our instance value. This would cause
// the transaction to instantiate its own, separate IOService to handle
// the transaction's IO.
NameChangeTransactionPtr trans;
if (next_ncr->getChangeType() == dhcp_ddns::CHG_ADD) {
trans.reset(new NameAddTransaction(io_service_, next_ncr,
forward_domain, reverse_domain));
} else {
trans.reset(new NameRemoveTransaction(io_service_, next_ncr,
forward_domain, reverse_domain));
}
// Add the new transaction to the list.
transaction_list_[key] = trans;
// Start it.
trans->startTransaction();
}
TransactionList::iterator
......@@ -189,6 +199,11 @@ D2UpdateMgr::removeTransaction(const TransactionKey& key) {
}
}
TransactionList::iterator
D2UpdateMgr::transactionListBegin() {
return (transaction_list_.begin());
}
TransactionList::iterator
D2UpdateMgr::transactionListEnd() {
return (transaction_list_.end());
......
......@@ -162,6 +162,13 @@ protected:
void makeTransaction(isc::dhcp_ddns::NameChangeRequestPtr& ncr);
public:
/// @brief Gets the UpdateMgr's IOService.
///
/// @return returns a reference to the IOService
const IOServicePtr& getIOService() {
return (io_service_);
}
/// @brief Returns the maximum number of concurrent transactions.
size_t getMaxTransactions() const {
return (max_transactions_);
......@@ -187,6 +194,9 @@ public:
/// @brief Returns the transaction list end position.
TransactionList::iterator transactionListEnd();
/// @brief Returns the transaction list beg position.
TransactionList::iterator transactionListBegin();
/// @brief Convenience method that checks transaction list for the given key
///
/// @param key the transaction key value for which to search.
......
......@@ -45,7 +45,7 @@ public:
// A buffer holding response from a DNS.
util::OutputBufferPtr in_buf_;
// A caller-supplied object holding a parsed response from DNS.
D2UpdateMessagePtr response_;
D2UpdateMessagePtr& response_;
// A caller-supplied external callback which is invoked when DNS message
// exchange is complete or interrupted.
DNSClient::Callback* callback_;
......@@ -104,12 +104,6 @@ DNSClientImpl::DNSClientImpl(D2UpdateMessagePtr& response_placeholder,
<< proto_ << "' specified for DNS Updates");
}
}
if (!response_) {
isc_throw(BadValue, "a pointer to an object to encapsulate the DNS"
" server must be provided; found NULL value");
}
}
DNSClientImpl::~DNSClientImpl() {
......@@ -122,6 +116,11 @@ DNSClientImpl::operator()(asiodns::IOFetch::Result result) {
DNSClient::Status status = getStatus(result);
if (status == DNSClient::SUCCESS) {
InputBuffer response_buf(in_buf_->getData(), in_buf_->getLength());
// Allocate a new response message. (Note that Message::fromWire
// may only be run once per message, so we need to start fresh
// each time.)
response_.reset(new D2UpdateMessage(D2UpdateMessage::INBOUND));
// Server's response may be corrupted. In such case, fromWire will
// throw an exception. We want to catch this exception to return
// appropriate status code to the caller and log this event.
......
......@@ -230,7 +230,7 @@ NameAddTransaction::addingFwdAddrsHandler() {
// If we get not authorized should we try the next server in
// the list? @todo This needs some discussion perhaps.
LOG_ERROR(dctl_logger, DHCP_DDNS_FORWARD_ADD_REJECTED)
.arg(getCurrentServer()->getIpAddress())
.arg(getCurrentServer()->toText())
.arg(getNcr()->getFqdn())
.arg(rcode.getCode());
transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
......@@ -247,7 +247,7 @@ NameAddTransaction::addingFwdAddrsHandler() {
// is not entirely clear if this is accurate.
LOG_ERROR(dctl_logger, DHCP_DDNS_FORWARD_ADD_IO_ERROR)
.arg(getNcr()->getFqdn())
.arg(getCurrentServer()->getIpAddress());
.arg(getCurrentServer()->toText());
retryTransition(SELECTING_FWD_SERVER_ST);
break;
......@@ -256,7 +256,7 @@ NameAddTransaction::addingFwdAddrsHandler() {
// A response was received but was corrupt. Retry it like an IO
// error.
LOG_ERROR(dctl_logger, DHCP_DDNS_FORWARD_ADD_RESP_CORRUPT)
.arg(getCurrentServer()->getIpAddress())
.arg(getCurrentServer()->toText())
.arg(getNcr()->getFqdn());
retryTransition(SELECTING_FWD_SERVER_ST);
......@@ -268,7 +268,7 @@ NameAddTransaction::addingFwdAddrsHandler() {
LOG_ERROR(dctl_logger, DHCP_DDNS_FORWARD_ADD_BAD_DNSCLIENT_STATUS)
.arg(getDnsUpdateStatus())
.arg(getNcr()->getFqdn())
.arg(getCurrentServer()->getIpAddress());
.arg(getCurrentServer()->toText());
transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
break;
......@@ -342,7 +342,7 @@ NameAddTransaction::replacingFwdAddrsHandler() {
// If we get not authorized should try the next server in
// the list? @todo This needs some discussion perhaps.
LOG_ERROR(dctl_logger, DHCP_DDNS_FORWARD_REPLACE_REJECTED)
.arg(getCurrentServer()->getIpAddress())
.arg(getCurrentServer()->toText())
.arg(getNcr()->getFqdn())
.arg(rcode.getCode());
transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
......@@ -359,7 +359,7 @@ NameAddTransaction::replacingFwdAddrsHandler() {
// is not entirely clear if this is accurate.
LOG_ERROR(dctl_logger, DHCP_DDNS_FORWARD_REPLACE_IO_ERROR)
.arg(getNcr()->getFqdn())
.arg(getCurrentServer()->getIpAddress());
.arg(getCurrentServer()->toText());
// If we are out of retries on this server, we go back and start
// all over on a new server.
......@@ -370,7 +370,7 @@ NameAddTransaction::replacingFwdAddrsHandler() {
// A response was received but was corrupt. Retry it like an IO
// error.
LOG_ERROR(dctl_logger, DHCP_DDNS_FORWARD_REPLACE_RESP_CORRUPT)
.arg(getCurrentServer()->getIpAddress())
.arg(getCurrentServer()->toText())
.arg(getNcr()->getFqdn());
// If we are out of retries on this server, we go back and start
......@@ -385,7 +385,7 @@ NameAddTransaction::replacingFwdAddrsHandler() {
DHCP_DDNS_FORWARD_REPLACE_BAD_DNSCLIENT_STATUS)
.arg(getDnsUpdateStatus())
.arg(getNcr()->getFqdn())
.arg(getCurrentServer()->getIpAddress());
.arg(getCurrentServer()->toText());
transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
break;
......@@ -476,7 +476,7 @@ NameAddTransaction::replacingRevPtrsHandler() {
// If we get not authorized should try the next server in
// the list? @todo This needs some discussion perhaps.
LOG_ERROR(dctl_logger, DHCP_DDNS_REVERSE_REPLACE_REJECTED)
.arg(getCurrentServer()->getIpAddress())
.arg(getCurrentServer()->toText())
.arg(getNcr()->getFqdn())
.arg(rcode.getCode());
transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
......@@ -493,7 +493,7 @@ NameAddTransaction::replacingRevPtrsHandler() {
// is not entirely clear if this is accurate.
LOG_ERROR(dctl_logger, DHCP_DDNS_REVERSE_REPLACE_IO_ERROR)
.arg(getNcr()->getFqdn())
.arg(getCurrentServer()->getIpAddress());
.arg(getCurrentServer()->toText());
// If we are out of retries on this server, we go back and start
// all over on a new server.
......@@ -504,7 +504,7 @@ NameAddTransaction::replacingRevPtrsHandler() {
// A response was received but was corrupt. Retry it like an IO
// error.
LOG_ERROR(dctl_logger, DHCP_DDNS_REVERSE_REPLACE_RESP_CORRUPT)
.arg(getCurrentServer()->getIpAddress())
.arg(getCurrentServer()->toText())
.arg(getNcr()->getFqdn());
// If we are out of retries on this server, we go back and start
......@@ -519,7 +519,7 @@ NameAddTransaction::replacingRevPtrsHandler() {
DHCP_DDNS_REVERSE_REPLACE_BAD_DNSCLIENT_STATUS)
.arg(getDnsUpdateStatus())
.arg(getNcr()->getFqdn())
.arg(getCurrentServer()->getIpAddress());
.arg(getCurrentServer()->toText());
transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
break;
......
......@@ -225,7 +225,7 @@ NameRemoveTransaction::removingFwdAddrsHandler() {
// If we get not authorized should we try the next server in
// the list? @todo This needs some discussion perhaps.
LOG_ERROR(dctl_logger, DHCP_DDNS_FORWARD_REMOVE_ADDRS_REJECTED)
.arg(getCurrentServer()->getIpAddress())
.arg(getCurrentServer()->toText())
.arg(getNcr()->getFqdn())
.arg(rcode.getCode());
transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
......@@ -242,7 +242,7 @@ NameRemoveTransaction::removingFwdAddrsHandler() {
// is not entirely clear if this is accurate.
LOG_ERROR(dctl_logger, DHCP_DDNS_FORWARD_REMOVE_ADDRS_IO_ERROR)
.arg(getNcr()->getFqdn())
.arg(getCurrentServer()->getIpAddress());
.arg(getCurrentServer()->toText());
retryTransition(SELECTING_FWD_SERVER_ST);
break;
......@@ -251,7 +251,7 @@ NameRemoveTransaction::removingFwdAddrsHandler() {
// A response was received but was corrupt. Retry it like an IO
// error.
LOG_ERROR(dctl_logger, DHCP_DDNS_FORWARD_REMOVE_ADDRS_RESP_CORRUPT)
.arg(getCurrentServer()->getIpAddress())
.arg(getCurrentServer()->toText())
.arg(getNcr()->getFqdn());
retryTransition(SELECTING_FWD_SERVER_ST);
......@@ -264,7 +264,7 @@ NameRemoveTransaction::removingFwdAddrsHandler() {
DHCP_DDNS_FORWARD_REMOVE_ADDRS_BAD_DNSCLIENT_STATUS)
.arg(getDnsUpdateStatus())
.arg(getNcr()->getFqdn())
.arg(getCurrentServer()->getIpAddress());
.arg(getCurrentServer()->toText());
transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
break;
......@@ -340,7 +340,7 @@ NameRemoveTransaction::removingFwdRRsHandler() {
// If we get not authorized should try the next server in
// the list? @todo This needs some discussion perhaps.
LOG_ERROR(dctl_logger, DHCP_DDNS_FORWARD_REMOVE_RRS_REJECTED)
.arg(getCurrentServer()->getIpAddress())
.arg(getCurrentServer()->toText())
.arg(getNcr()->getFqdn())
.arg(rcode.getCode());
transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
......@@ -357,7 +357,7 @@ NameRemoveTransaction::removingFwdRRsHandler() {
// is not entirely clear if this is accurate.
LOG_ERROR(dctl_logger, DHCP_DDNS_FORWARD_REMOVE_RRS_IO_ERROR)
.arg(getNcr()->getFqdn())
.arg(getCurrentServer()->getIpAddress());
.arg(getCurrentServer()->toText());
// @note If we exhaust the IO retries for the current server
// due to IO failures, we will abort the remaining updates.
......@@ -374,7 +374,7 @@ NameRemoveTransaction::removingFwdRRsHandler() {
// A response was received but was corrupt. Retry it like an IO
// error.
LOG_ERROR(dctl_logger, DHCP_DDNS_FORWARD_REMOVE_RRS_RESP_CORRUPT)
.arg(getCurrentServer()->getIpAddress())
.arg(getCurrentServer()->toText())
.arg(getNcr()->getFqdn());
// If we are out of retries on this server abandon the transaction.
......@@ -389,7 +389,7 @@ NameRemoveTransaction::removingFwdRRsHandler() {
DHCP_DDNS_FORWARD_REMOVE_RRS_BAD_DNSCLIENT_STATUS)
.arg(getDnsUpdateStatus())
.arg(getNcr()->getFqdn())
.arg(getCurrentServer()->getIpAddress());
.arg(getCurrentServer()->toText());
transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
break;
......@@ -483,7 +483,7 @@ NameRemoveTransaction::removingRevPtrsHandler() {
// If we get not authorized should try the next server in
// the list? @todo This needs some discussion perhaps.
LOG_ERROR(dctl_logger, DHCP_DDNS_REVERSE_REMOVE_REJECTED)
.arg(getCurrentServer()->getIpAddress())
.arg(getCurrentServer()->toText())
.arg(getNcr()->getFqdn())
.arg(rcode.getCode());
transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
......@@ -500,7 +500,7 @@ NameRemoveTransaction::removingRevPtrsHandler() {
// is not entirely clear if this is accurate.
LOG_ERROR(dctl_logger, DHCP_DDNS_REVERSE_REMOVE_IO_ERROR)
.arg(getNcr()->getFqdn())
.arg(getCurrentServer()->getIpAddress());
.arg(getCurrentServer()->toText());
// If we are out of retries on this server, we go back and start
// all over on a new server.
......@@ -511,7 +511,7 @@ NameRemoveTransaction::removingRevPtrsHandler() {
// A response was received but was corrupt. Retry it like an IO
// error.
LOG_ERROR(dctl_logger, DHCP_DDNS_REVERSE_REMOVE_RESP_CORRUPT)
.arg(getCurrentServer()->getIpAddress())
.arg(getCurrentServer()->toText())
.arg(getNcr()->getFqdn());
// If we are out of retries on this server, we go back and start
......@@ -526,7 +526,7 @@ NameRemoveTransaction::removingRevPtrsHandler() {
DHCP_DDNS_REVERSE_REMOVE_BAD_DNSCLIENT_STATUS)
.arg(getDnsUpdateStatus())
.arg(getNcr()->getFqdn())
.arg(getCurrentServer()->getIpAddress());
.arg(getCurrentServer()->toText());
transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
break;
......
......@@ -80,6 +80,7 @@ NameChangeTransaction::~NameChangeTransaction(){
void
NameChangeTransaction::startTransaction() {
setNcrStatus(dhcp_ddns::ST_PENDING);
startModel(READY_ST);
}
......@@ -89,6 +90,12 @@ NameChangeTransaction::operator()(DNSClient::Status status) {
// set to indicate IO completed.
// runModel is exception safe so we are good to call it here.
// It won't exit until we hit the next IO wait or the state model ends.
LOG_DEBUG(dctl_logger, DBGLVL_TRACE_DETAIL,
DHCP_DDNS_UPDATE_RESPONSE_RECEIVED)
.arg(getTransactionKey().toStr())
.arg(current_server_->toText())
.arg(status);
setDnsUpdateStatus(status);
runModel(IO_COMPLETED_EVT);
}
......@@ -109,6 +116,10 @@ NameChangeTransaction::sendUpdate(bool /* use_tsig_ */) {
// Message is on its way, so the next event should be NOP_EVT.
postNextEvent(NOP_EVT);
LOG_DEBUG(dctl_logger, DBGLVL_TRACE_DETAIL,
DHCP_DDNS_UPDATE_REQUEST_SENT)
.arg(getTransactionKey().toStr())
.arg(current_server_->toText());
} catch (const std::exception& ex) {
// We were unable to initiate the send.
// It is presumed that any throw from doUpdate is due to a programmatic
......@@ -200,6 +211,7 @@ NameChangeTransaction::setDnsUpdateRequest(D2UpdateMessagePtr& request) {
void
NameChangeTransaction::clearDnsUpdateRequest() {
update_attempts_ = 0;
dns_update_request_.reset();
}
......
......@@ -152,7 +152,15 @@ public:
//@}
/// @brief Defualt time to assign to a single DNS udpate.
#if 0
/// @todo This value will be configurable in the near future, but
/// until it is there is no way to replace its value. For now
/// we will define it to be relatively short, so unit tests will
/// run within reasonable amount of time.
static const unsigned int DNS_UPDATE_DEFAULT_TIMEOUT = 5 * 1000;
#else
static const unsigned int DNS_UPDATE_DEFAULT_TIMEOUT = 100;
#endif
/// @brief Maximum times to attempt a single update on a given server.
static const unsigned int MAX_UPDATE_TRIES_PER_SERVER = 3;
......@@ -287,7 +295,8 @@ protected:
/// @param request is the new request packet to assign.
void setDnsUpdateRequest(D2UpdateMessagePtr& request);
/// @brief Destroys the current update request packet.
/// @brief Destroys the current update request packet and resets
/// udpate attempts count..
void clearDnsUpdateRequest();
/// @brief Sets the update status to the given status value.
......@@ -341,17 +350,6 @@ protected:
/// servers from which to select.
bool selectNextServer();
/// @brief Fetches the currently selected server.
///
/// @return A const pointer reference to the DnsServerInfo of the current
/// server.
const DnsServerInfoPtr& getCurrentServer() const;
/// @brief Fetches the DNSClient instance
///
/// @return A const pointer reference to the DNSClient
const DNSClientPtr& getDNSClient() const;
/// @brief Sets the update attempt count to the given value.
///
/// @param value is the new value to assign.
......@@ -445,6 +443,17 @@ public:
/// the request does not include a reverse change, the pointer will empty.
DdnsDomainPtr& getReverseDomain();
/// @brief Fetches the currently selected server.
///
/// @return A const pointer reference to the DnsServerInfo of the current
/// server.
const DnsServerInfoPtr& getCurrentServer() const;
/// @brief Fetches the DNSClient instance
///
/// @return A const pointer reference to the DNSClient
const DNSClientPtr& getDNSClient() const;
/// @brief Fetches the current DNS update request packet.
///
/// @return A const pointer reference to the current D2UpdateMessage
......
This diff is collapsed.
......@@ -25,6 +25,7 @@
#include <boost/bind.hpp>
#include <boost/scoped_ptr.hpp>
#include <gtest/gtest.h>
#include <nc_test_utils.h>
using namespace std;
using namespace isc;
......@@ -69,6 +70,8 @@ public:
bool corrupt_response_;
bool expect_response_;
asiolink::IntervalTimer test_timer_;
int received_;
int expected_;
// @brief Constructor.
//
......@@ -83,7 +86,8 @@ public:
status_(DNSClient::SUCCESS),
corrupt_response_(false),
expect_response_(true),
test_timer_(service_) {
test_timer_(service_),
received_(0), expected_(0) {
asiodns::logger.setSeverity(isc::log::INFO);
response_.reset(new D2UpdateMessage(D2UpdateMessage::INBOUND));
dns_client_.reset(new DNSClient(response_, this));
......@@ -108,7 +112,10 @@ public:
// @param status A status code returned by DNSClient.
virtual void operator()(DNSClient::Status status) {
status_ = status;
service_.stop();
if (!expected_ || (expected_ == ++received_))
{
service_.stop();
}
if (expect_response_) {
if (!corrupt_response_) {
......@@ -121,7 +128,7 @@ public:
response_->getRRCount(D2UpdateMessage::SECTION_ZONE));
D2ZonePtr zone = response_->getZone();
ASSERT_TRUE(zone);
EXPECT_EQ("example.com.", zone->getName().toText());
EXPECT_EQ("response.example.com.", zone->getName().toText());
EXPECT_EQ(RRClass::IN().getCode(), zone->getClass().getCode());
} else {
......@@ -187,9 +194,6 @@ public:
// It also verifies that the constructor will not throw if the supplied
// callback object is NULL.
void runConstructorTest() {
D2UpdateMessagePtr null_response;
EXPECT_THROW(DNSClient(null_response, this, DNSClient::UDP),
isc::BadValue);
EXPECT_NO_THROW(DNSClient(response_, NULL, DNSClient::UDP));
// The TCP Transport is not supported right now. So, we return exception
......@@ -284,7 +288,7 @@ public:
// Create a request DNS Update message.
D2UpdateMessage message(D2UpdateMessage::OUTBOUND);
ASSERT_NO_THROW(message.setRcode(Rcode(Rcode::NOERROR_CODE)));
ASSERT_NO_THROW(message.setZone(Name("example.com"), RRClass::IN()));
ASSERT_NO_THROW(message.setZone(Name("response.example.com"), RRClass::IN()));
// In order to perform the full test, when the client sends the request
// and receives a response from the server, we have to emulate the
......@@ -322,11 +326,13 @@ public:
// The socket is now ready to receive the data. Let's post some request
// message then.
const int timeout = 5;
expected_++;
dns_client_->doUpdate(service_, IOAddress(TEST_ADDRESS), TEST_PORT,
message, timeout);
// It is possible to request that two packets are sent concurrently.
if (two_sends) {
expected_++;
dns_client_->doUpdate(service_, IOAddress(TEST_ADDRESS), TEST_PORT,
message, timeout);
......@@ -338,6 +344,10 @@ public:
udp_socket.close();
// Since the callback, operator(), calls stop() on the io_service,
// we must reset it in order for subsequent calls to run() or
// run_one() to work.
service_.get_io_service().reset();
}
};
......@@ -393,6 +403,7 @@ TEST_F(DNSClientTest, sendReceiveCurrupted) {
TEST_F(DNSClientTest, sendReceiveTwice) {
runSendReceiveTest(false, false);
runSendReceiveTest(false, false);
EXPECT_EQ(2, received_);
}
// Verify that it is possible to use the DNSClient instance to perform the
......@@ -401,7 +412,13 @@ TEST_F(DNSClientTest, sendReceiveTwice) {
// 2. send
// 3. receive
// 4. receive
TEST_F(DNSClientTest, concurrentSendReceive) {
// @todo THIS Test does not function. The method runSendReceive only
// schedules one "server" receive. In other words only one request is
// listened for and then received. Once it is received, the operator()
// method calls stop() on the io_service, which causes the second receive
// to be cancelled. It is also unclear, what the asio layer does with a
// second receive on the same socket.
TEST_F(DNSClientTest, DISABLED_concurrentSendReceive) {
runSendReceiveTest(false, true);
}
......
......@@ -37,7 +37,8 @@ const bool NO_RDATA = false;