summaryrefslogtreecommitdiffstats
path: root/src/lib/d2srv/dns_client.h
blob: c63a7a0c0a07000cd940051f357faf7e904647cd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
// Copyright (C) 2013-2021 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#ifndef DNS_CLIENT_H
#define DNS_CLIENT_H

#include <asiolink/io_service.h>
#include <asiodns/io_fetch.h>
#include <d2srv/d2_tsig_key.h>
#include <d2srv/d2_update_message.h>
#include <util/buffer.h>

namespace isc {
namespace d2 {

class DNSClient;
typedef boost::shared_ptr<DNSClient> DNSClientPtr;

/// DNSClient class implementation.
class DNSClientImpl;

/// @brief The @c DNSClient class handles communication with the DNS server.
///
/// Communication with the DNS server is asynchronous. Caller must provide a
/// callback, which will be invoked when the response from the DNS server is
/// received, a timeout has occurred or IO service has been stopped for any
/// reason. The caller-supplied callback is called by the internal callback
/// operator implemented by @c DNSClient. This callback is responsible for
/// initializing the @c D2UpdateMessage instance which encapsulates the response
/// from the DNS. This initialization does not take place if the response from
/// DNS is not received.
///
/// Caller must supply a pointer to the @c D2UpdateMessage object, which will
/// encapsulate DNS response, through class constructor. An exception will be
/// thrown if the pointer is not initialized by the caller.
///
/// @todo Ultimately, this class will support both TCP and UDP Transport.
/// Currently only UDP is supported and can be specified as a preferred
/// protocol. @c DNSClient constructor will throw an exception if TCP is
/// specified. Once both protocols are supported, the @c DNSClient logic will
/// try to obey caller's preference. However, it may use the other protocol if
/// on its own discretion, when there is a legitimate reason to do so. For
/// example, if communication with the server using preferred protocol fails.
class DNSClient {
public:

    /// @brief Transport layer protocol used by a DNS Client to communicate
    /// with a server.
    enum Protocol {
        UDP,
        TCP
    };

    /// @brief A status code of the DNSClient.
    enum Status {
        SUCCESS,           ///< Response received and is ok.
        TIMEOUT,           ///< No response, timeout.
        IO_STOPPED,        ///< IO was stopped.
        INVALID_RESPONSE,  ///< Response received but invalid.
        OTHER              ///< Other, unclassified error.
    };

    /// @brief Callback for the @c DNSClient class.
    ///
    /// This is an abstract class which represents the external callback for the
    /// @c DNSClient. Caller must implement this class and supply its instance
    /// in the @c DNSClient constructor to get callbacks when the DNS Update
    /// exchange is complete (@see @c DNSClient).
    class Callback {
    public:
        /// @brief Virtual destructor.
        virtual ~Callback() { }

        /// @brief Function operator implementing a callback.
        ///
        /// @param status a @c DNSClient::Status enum representing status code
        /// of DNSClient operation.
        virtual void operator()(DNSClient::Status status) = 0;
    };

    /// @brief Constructor.
    ///
    /// @param response_placeholder Message object pointer which will be updated
    /// with dynamically allocated object holding the DNS server's response.
    /// @param callback Pointer to an object implementing @c DNSClient::Callback
    /// class. This object will be called when DNS message exchange completes or
    /// if an error occurs. NULL value disables callback invocation.
    /// @param proto caller's preference regarding Transport layer protocol to
    /// be used by DNS Client to communicate with a server.
    DNSClient(D2UpdateMessagePtr& response_placeholder, Callback* callback,
              const Protocol proto = UDP);

    /// @brief Virtual destructor, does nothing.
    ~DNSClient();

    ///
    /// @name Copy constructor and assignment operator
    ///
    /// Copy constructor and assignment operator are private because there are
    /// no use cases when a DNSClient instance will need to be copied. Also, it
    /// is desired to avoid copying a DNSClient::impl_ pointer and external
    /// callbacks.
    ///
    //@{
private:
    DNSClient(const DNSClient& source);
    DNSClient& operator=(const DNSClient& source);
    //@}

public:

    /// @brief Returns maximal allowed timeout value accepted by
    /// @c DNSClient::doUpdate.
    ///
    /// @return maximal allowed timeout value accepted by @c DNSClient::doUpdate
    static unsigned int getMaxTimeout();

    /// @brief Start asynchronous DNS Update with TSIG.
    ///
    /// This function starts asynchronous DNS Update and returns. The DNS Update
    /// will be executed by the specified IO service. Once the message exchange
    /// with a DNS server is complete, timeout occurs or IO operation is
    /// interrupted, the caller-supplied callback function will be invoked.
    ///
    /// An address and port of the DNS server is specified through the function
    /// arguments so as the same instance of the @c DNSClient can be used to
    /// initiate multiple message exchanges.
    ///
    /// @param io_service IO service to be used to run the message exchange.
    /// @param ns_addr DNS server address.
    /// @param ns_port DNS server port.
    /// @param update A DNS Update message to be sent to the server.
    /// @param wait A timeout (in milliseconds) for the response. If a response
    /// is not received within the timeout, exchange is interrupted. This value
    /// must not exceed maximal value for 'int' data type.
    /// @param tsig_key A pointer to an @c D2TsigKeyPtr object that will
    /// (if not null) be used to sign the DNS Update message and verify the
    /// response.
    void doUpdate(asiolink::IOService& io_service,
                  const asiolink::IOAddress& ns_addr,
                  const uint16_t ns_port,
                  D2UpdateMessage& update,
                  const unsigned int wait,
                  const D2TsigKeyPtr& tsig_key = D2TsigKeyPtr());

private:
    /// @brief Pointer to DNSClient implementation.
    std::unique_ptr<DNSClientImpl> impl_;
};

} // namespace d2
} // namespace isc

#endif // DNS_CLIENT_H