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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
// Copyright (C) 2010-2024 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 IO_FETCH_H
#define IO_FETCH_H

#include <config.h>

// We want to use coroutine.hpp from the system's boost headers if possible.
// However, very old Boost versions (provided by RHEL 7 or CentOS 7) didn't have
// this header. So we can resort to our bundled version, but only if necessary.
#ifdef HAVE_BOOST_ASIO_COROUTINE_HPP
#include <boost/asio/coroutine.hpp><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#else
#include <ext/coroutine/coroutine.hpp>
#endif

#include <asiolink/io_address.h>
#include <asiolink/io_service.h>
#include <dns/message.h>
#include <dns/question.h>
#include <util/buffer.h>

#include <boost/shared_array.hpp><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <boost/shared_ptr.hpp><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <boost/date_time/posix_time/posix_time_types.hpp><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <boost/system/error_code.hpp><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.

namespace isc {
namespace asiodns {

// Forward declarations
struct IOFetchData;

/// @brief Upstream Fetch Processing.
///
/// IOFetch is the class used to send upstream fetches and to handle responses.
class IOFetch : public boost::asio::coroutine {
public:
    /// @brief Protocol to use on the fetch
    enum Protocol {
        UDP = 0,
        TCP = 1
    };

    /// @brief Origin of Asynchronous I/O Call.
    ///
    /// Indicates what initiated an asynchronous I/O call and used in deciding what
    /// error message to output if the I/O fails.
    enum Origin {
        NONE = 0,          // No asynchronous call outstanding
        OPEN = 1,
        SEND = 2,
        RECEIVE = 3,
        CLOSE = 4
    };

    /// @brief Result of Upstream Fetch.
    ///
    /// @note that this applies to the status of I/Os in the fetch - a fetch that
    /// resulted in a packet being received from the server is a SUCCESS, even if
    /// the contents of the packet indicate that some error occurred.
    enum Result {
        SUCCESS = 0,       // Success, fetch completed
        TIME_OUT = 1,      // Failure, fetch timed out
        STOPPED = 2,       // Control code, fetch has been stopped
        NOTSET = 3         // For testing, indicates value not set
    };

    /// @note The next enum is a "trick" to allow constants to be defined in a class
    /// declaration.

    /// @brief Integer Constants.
    enum {
        STAGING_LENGTH = 8192   // Size of staging buffer
    };

    /// @brief I/O Fetch Callback.
    ///
    /// Class of callback object for when the fetch itself has completed - an object
    /// of this class is passed to the IOFetch constructor and its operator() method
    /// called when the fetch completes.
    ///
    /// @note The difference between the two operator() methods:
    /// - IOFetch::operator() callback is called when an asynchronous I/O has completed.
    /// - IOFetch::Callback::operator() is called when an upstream fetch - which may
    ///   have involved several asynchronous I/O operations - has completed.
    ///
    /// This is an abstract class.
    class Callback {
    public:
        /// @brief Constructor.
        Callback() = default;

        /// @brief Destructor.
        virtual ~Callback() = default;

        /// @brief Callback method.
        ///
        /// This method is called when the fetch completes.
        ///
        /// @param result Result of the fetch.
        virtual void operator()(Result result) = 0;
    };

    /// @brief Constructor.
    ///
    /// Creates the object that will handle the upstream fetch.
    ///
    /// @param protocol Fetch protocol, either IOFetch::TCP or IOFetch::UDP.
    /// @param service I/O Service object to handle the asynchronous
    ///        operations.
    /// @param question DNS question to send to the upstream server.
    /// @param address IP address of upstream server.
    /// @param port Port to which to connect on the upstream server.
    /// @param buff Output buffer into which the response (in wire format)
    ///        is written (if a response is received).
    /// @param cb Callback object containing the callback to be called when we
    ///        terminate.  The caller is responsible for managing this object
    ///        and deleting it if necessary.
    /// @param wait Timeout for the fetch (in ms).  The default value of
    ///        -1 indicates no timeout.
    /// @param edns true if the request should be EDNS. The default value is
    ///        true.
    IOFetch(Protocol protocol,
            const isc::asiolink::IOServicePtr& service,
            const isc::dns::Question& question,
            const isc::asiolink::IOAddress& address,
            uint16_t port,
            isc::util::OutputBufferPtr& buff,
            Callback* cb,
            int wait = -1,
            bool edns = true);

    /// @brief Constructor
    ///
    /// This constructor has one parameter "query_message", which is the shared_ptr
    /// to a full query message. It's different with above constructor which has only
    /// question section. All other parameters are the same.
    ///
    /// @param protocol Fetch protocol, either IOFetch::TCP or IOFetch::UDP.
    /// @param service I/O Service object to handle the asynchronous
    ///        operations.
    /// @param query_message the shared_ptr to a full query message got from a
    ///        query client.
    /// @param address IP address of upstream server.
    /// @param port Port to which to connect on the upstream server.
    /// @param buff Output buffer into which the response (in wire format)
    ///        is written (if a response is received).
    /// @param cb Callback object containing the callback to be called when we
    ///        terminate.  The caller is responsible for managing this object
    ///        and deleting it if necessary.
    /// @param wait Timeout for the fetch (in ms).  The default value of -1
    ///        indicates no timeout.
    IOFetch(Protocol protocol,
            const isc::asiolink::IOServicePtr& service,
            isc::dns::ConstMessagePtr query_message,
            const isc::asiolink::IOAddress& address,
            uint16_t port,
            isc::util::OutputBufferPtr& buff,
            Callback* cb,
            int wait = -1);

    /// @brief Constructor.
    ///
    /// Creates the object that will handle the upstream fetch.
    ///
    /// @param protocol Fetch protocol, either IOFetch::TCP or IOFetch::UDP
    /// @param service I/O Service object to handle the asynchronous
    ///     operations.
    /// @param outpkt Packet to send to upstream server.  Note that the
    ///     QID (first two bytes of the packet) may be altered in the sending.
    /// @param buff Output buffer into which the response (in wire format)
    ///     is written (if a response is received).
    /// @param cb Callback object containing the callback to be called
    ///     when we terminate.  The caller is responsible for managing this
    ///     object and deleting it if necessary.
    /// @param address IP address of upstream server.
    /// @param port Port to which to connect on the upstream server
    ///     (default = 53).
    /// @param wait Timeout for the fetch (in ms).  The default value of
    ///     -1 indicates no timeout.
    IOFetch(Protocol protocol,
            const isc::asiolink::IOServicePtr& service,
            isc::util::OutputBufferPtr& outpkt,
            const isc::asiolink::IOAddress& address,
            uint16_t port,
            isc::util::OutputBufferPtr& buff,
            Callback* cb,
            int wait = -1);

    /// @brief Return Current Protocol.
    ///
    /// @return Protocol associated with this IOFetch object.
    Protocol getProtocol() const;

    /// @brief Coroutine entry point.
    ///
    /// The operator() method is the method in which the coroutine code enters
    /// this object when an operation has been completed.
    ///
    /// @param ec Error code, the result of the last asynchronous I/O operation.
    /// @param length Amount of data received on the last asynchronous read.
    void operator()(boost::system::error_code ec = boost::system::error_code(),
                    size_t length = 0);

    /// @brief Terminate query.
    ///
    /// This method can be called at any point.  It terminates the current
    /// query with the specified reason.
    /// This function stops the coroutine sequence.  It is called either when the
    /// query finishes or when the timer times out.  Either way, it sets the
    /// "stopped_" flag and cancels anything that is in progress.
    ///
    /// As the function may be entered multiple times as things wind down, it checks
    /// if the stopped_ flag is already set.  If it is, the call is a no-op.
    ///
    /// @param reason Reason for terminating the query.
    void stop(Result reason = STOPPED);

private:
    /// @brief IOFetch Initialization Function.
    ///
    /// All the parameters are same with the constructor, except parameter
    /// "query_message".
    ///
    /// @param query_message the message to be sent out.
    void initIOFetch(isc::dns::MessagePtr& query_message,
                     Protocol protocol,
                     const isc::asiolink::IOServicePtr& service,
                     const isc::dns::Question& question,
                     const isc::asiolink::IOAddress& address,
                     uint16_t port,
                     isc::util::OutputBufferPtr& buff,
                     Callback* cb, int wait,
                     bool edns = true);

    /// @brief Log I/O Failure.
    ///
    /// Records an I/O failure to the log file.
    ///
    /// @param ec ASIO error code.
    void logIOFailure(boost::system::error_code ec);

    /// @brief data which is a structure pointed to by a shared pointer.  The IOFetch
    /// object is copied a number of times during its life, and only requiring a
    /// pointer to be copied reduces overhead.
    boost::shared_ptr<IOFetchData> data_;   ///< Private data
};

/// @brief Defines a pointer to an IOFetch.
typedef boost::shared_ptr<IOFetch> IOFetchPtr;

}  // namespace asiodns
}  // namespace isc

#endif // IO_FETCH_H