|
@@ -31,8 +31,44 @@ using namespace isc::util;
|
|
|
using namespace isc::asiolink;
|
|
|
using namespace isc::asiodns;
|
|
|
|
|
|
-DNSClient::DNSClient(D2UpdateMessagePtr& response_placeholder,
|
|
|
- Callback* callback)
|
|
|
+// This class provides the implementation for the DNSClient. This allows to
|
|
|
+// the separation of the DNSClient interface from the implementation details.
|
|
|
+// Currently, implementation uses IOFetch object to handle asynchronous
|
|
|
+// communication with the DNS. This design may be revisited in the future. If
|
|
|
+// implementation is changed, the DNSClient API will remain unchanged thanks
|
|
|
+// to this separation.
|
|
|
+class DNSClientImpl : public asiodns::IOFetch::Callback {
|
|
|
+public:
|
|
|
+ // A buffer holding response from a DNS.
|
|
|
+ util::OutputBufferPtr in_buf_;
|
|
|
+ // A caller-supplied object holding a parsed response from DNS.
|
|
|
+ D2UpdateMessagePtr response_;
|
|
|
+ // A caller-supplied external callback which is invoked when DNS message
|
|
|
+ // exchange is complete or interrupted.
|
|
|
+ DNSClient::Callback* callback_;
|
|
|
+
|
|
|
+ DNSClientImpl(D2UpdateMessagePtr& response_placeholder,
|
|
|
+ DNSClient::Callback* callback);
|
|
|
+ virtual ~DNSClientImpl();
|
|
|
+
|
|
|
+ // This internal callback is called when the DNS update message exchange is
|
|
|
+ // complete. It further invokes the external callback provided by a caller.
|
|
|
+ // Before external callback is invoked, an object of the D2UpdateMessage
|
|
|
+ // type, representing a response from the server is set.
|
|
|
+ virtual void operator()(asiodns::IOFetch::Result result);
|
|
|
+
|
|
|
+ void doUpdate(asiolink::IOService& io_service,
|
|
|
+ const asiolink::IOAddress& ns_addr,
|
|
|
+ const uint16_t ns_port,
|
|
|
+ D2UpdateMessage& update,
|
|
|
+ const int wait = -1);
|
|
|
+
|
|
|
+ // This function maps the IO error to the DNSClient error.
|
|
|
+ DNSClient::Status getStatus(const asiodns::IOFetch::Result);
|
|
|
+};
|
|
|
+
|
|
|
+DNSClientImpl::DNSClientImpl(D2UpdateMessagePtr& response_placeholder,
|
|
|
+ DNSClient::Callback* callback)
|
|
|
: in_buf_(new OutputBuffer(DEFAULT_BUFFER_SIZE)),
|
|
|
response_(response_placeholder), callback_(callback) {
|
|
|
if (!response_) {
|
|
@@ -41,29 +77,56 @@ DNSClient::DNSClient(D2UpdateMessagePtr& response_placeholder,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+DNSClientImpl::~DNSClientImpl() {
|
|
|
+}
|
|
|
+
|
|
|
void
|
|
|
-DNSClient::operator()(IOFetch::Result result) {
|
|
|
+DNSClientImpl::operator()(asiodns::IOFetch::Result result) {
|
|
|
// @todo More sanity checks here. Also, there is a question, what happens if
|
|
|
// the exception is thrown here.
|
|
|
|
|
|
- if (result == IOFetch::SUCCESS) {
|
|
|
+ DNSClient::Status status = getStatus(result);
|
|
|
+
|
|
|
+ if (status == DNSClient::SUCCESS) {
|
|
|
InputBuffer response_buf(in_buf_->getData(), in_buf_->getLength());
|
|
|
- response_->fromWire(response_buf);
|
|
|
+ try {
|
|
|
+ response_->fromWire(response_buf);
|
|
|
+ } catch (const Exception& ex) {
|
|
|
+ status = DNSClient::INVALID_RESPONSE;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// Once we are done with internal business, let's call a callback supplied
|
|
|
// by a caller.
|
|
|
if (callback_ != NULL) {
|
|
|
- (*callback_)(result);
|
|
|
+ (*callback_)(status);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+DNSClient::Status
|
|
|
+DNSClientImpl::getStatus(const asiodns::IOFetch::Result result) {
|
|
|
+ switch (result) {
|
|
|
+ case IOFetch::SUCCESS:
|
|
|
+ return (DNSClient::SUCCESS);
|
|
|
+
|
|
|
+ case IOFetch::TIME_OUT:
|
|
|
+ return (DNSClient::TIMEOUT);
|
|
|
+
|
|
|
+ case IOFetch::STOPPED:
|
|
|
+ return (DNSClient::IO_STOPPED);
|
|
|
+
|
|
|
+ default:
|
|
|
+ ;
|
|
|
}
|
|
|
+ return (DNSClient::OTHER);
|
|
|
}
|
|
|
|
|
|
void
|
|
|
-DNSClient::doUpdate(IOService& io_service,
|
|
|
- const IOAddress& ns_addr,
|
|
|
- const uint16_t ns_port,
|
|
|
- D2UpdateMessage& update,
|
|
|
- const int wait) {
|
|
|
+DNSClientImpl::doUpdate(IOService& io_service,
|
|
|
+ const IOAddress& ns_addr,
|
|
|
+ const uint16_t ns_port,
|
|
|
+ D2UpdateMessage& update,
|
|
|
+ const int wait) {
|
|
|
// A renderer is used by the toWire function which creates the on-wire data
|
|
|
// from the DNS Update message. A renderer has its internal buffer where it
|
|
|
// renders data by default. However, this buffer can't be directly accessed.
|
|
@@ -81,7 +144,7 @@ DNSClient::doUpdate(IOService& io_service,
|
|
|
// IOFetch has all the mechanisms that we need to perform asynchronous
|
|
|
// communication with the DNS server. The last but one argument points to
|
|
|
// this object as a completion callback for the message exchange. As a
|
|
|
- // result operator()(IOFetch::Result) will be called.
|
|
|
+ // result operator()(Status) will be called.
|
|
|
IOFetch io_fetch(IOFetch::UDP, io_service, msg_buf, ns_addr, ns_port,
|
|
|
in_buf_, this, wait);
|
|
|
// Post the task to the task queue in the IO service. Caller will actually
|
|
@@ -90,6 +153,25 @@ DNSClient::doUpdate(IOService& io_service,
|
|
|
}
|
|
|
|
|
|
|
|
|
+DNSClient::DNSClient(D2UpdateMessagePtr& response_placeholder,
|
|
|
+ Callback* callback)
|
|
|
+ : impl_(new DNSClientImpl(response_placeholder, callback)) {
|
|
|
+}
|
|
|
+
|
|
|
+DNSClient::~DNSClient() {
|
|
|
+ delete (impl_);
|
|
|
+}
|
|
|
+
|
|
|
+void
|
|
|
+DNSClient::doUpdate(IOService& io_service,
|
|
|
+ const IOAddress& ns_addr,
|
|
|
+ const uint16_t ns_port,
|
|
|
+ D2UpdateMessage& update,
|
|
|
+ const int wait) {
|
|
|
+ impl_->doUpdate(io_service, ns_addr, ns_port, update, wait);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
} // namespace d2
|
|
|
} // namespace isc
|
|
|
|