nameserver_entry.h 10.4 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.

15
16
#ifndef NAMESERVER_ENTRY_H
#define NAMESERVER_ENTRY_H
17
18
19

#include <string>
#include <vector>
20
#include <boost/enable_shared_from_this.hpp>
21

Michal Vaner's avatar
Michal Vaner committed
22
23
#include <exceptions/exceptions.h>
#include <dns/rrset.h>
24
#include <dns/rrtype.h>
Michal Vaner's avatar
Michal Vaner committed
25

26
27
#include <resolve/resolver_interface.h>

28
29
#include <util/lru_list.h>

30
#include "address_entry.h"
Michal Vaner's avatar
Michal Vaner committed
31
#include "nsas_types.h"
32
#include "hash_key.h"
Michal Vaner's avatar
Michal Vaner committed
33
#include "fetchable.h"
34
#include "nsas_entry.h"
35
#include "nameserver_address.h"
36
37
38
39

namespace isc {
namespace nsas {

40
41
class NameserverAddress;

42
43
44
45
46
47
48
49
50
51
52
/// \brief Inconsistent Owner Names
///
/// Thrown if a NameserverEntry is constructed from both an A and AAAA RRset
/// where the owner names do not match.
class InconsistentOwnerNames : public Exception {
public:
    InconsistentOwnerNames(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what)
    {}
};

53
54
55
56
57
58
59
60
61
62
/// \brief RTT is zero
///
/// Thrown if a RTT related with an address is 0.
class RTTIsZero : public Exception {
public:
    RTTIsZero(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what)
    {}
};

63
64
65
66
67
68
69
70
71
72
73
/// \brief Inconsistent Class
///
/// Thrown if a NameserverEntry is constructed from both an A and AAAA RRset
/// where the classes do not match.
class InconsistentClass : public Exception {
public:
    InconsistentClass(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what)
    {}
};

Michal Vaner's avatar
Michal Vaner committed
74
class ZoneEntry;
75
76
77
78
79
80
81
82
83
84
85
86

/// \brief Nameserver Entry
///
/// Describes a nameserver and its addresses.  A nameserver be authoritative
/// for several zones (hence is pointed to by more than one zone entry), and
/// may have several addresses associated with it.
///
/// The addresses expire after their TTL has been reached.  For simplicity,
/// (and because it is unlikely that A and AAAA records from the same zone have
/// different TTLs) there is one expiration time for all address records.
/// When that is reached, all records are declared expired and new fetches
/// started for the information.
87
88
///
/// As this object will be stored in the nameserver address store LRU list,
89
/// it is derived from the LRU list entry class.
90
91
///
/// It uses shared_from_this in its methods. It must live inside a shared_ptr.
92

93
class NameserverEntry : public NsasEntry<NameserverEntry>, public Fetchable {
94
95
public:
    /// List of addresses associated with this nameserver
96
    typedef std::vector<NameserverAddress>   AddressVector;
97
98
    typedef AddressVector::iterator     AddressVectorIterator;

99
    /// \brief Constructor where no A records are supplied.
100
101
    ///
    /// \param name Name of the nameserver,
102
    /// \param class_code class of the nameserver
Michal Vaner's avatar
Michal Vaner committed
103
104
105
    NameserverEntry(const std::string& name,
        const isc::dns::RRClass& class_code) :
        name_(name),
106
107
        classCode_(class_code),
        expiration_(0)
108
109
110
111
112
113
114
115
    {
        has_address_[V4_ONLY] = false;
        has_address_[V6_ONLY] = false;
        has_address_[ANY_OK] = false;
        expect_address_[V4_ONLY] = false;
        expect_address_[V6_ONLY] = false;
        expect_address_[ANY_OK] = false;
    }
116

117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
    /*
     * \brief Return Address
     *
     * Returns a vector of addresses corresponding to this nameserver.
     *
     * \param addresses Vector of address entries into which will be appended
     *     addresses that match the specified criteria. (The reason for
     *     choosing this signature is that addresses from more than one
     *     nameserver may be retrieved, in which case appending to an existing
     *     list of addresses is convenient.)
     * \param family The family of address that is requested.
     * \param expired_ok Return addresses even when expired. This is here
     *     because an address with TTL 0 is expired at the exact time it
     *     arrives. But when we call the callback, the owner of callback
     *     is allowed to use them anyway so it should set expired_ok
     *     to true.
     * \return The state this is currently in. If the TTL expires, it enters
     *     the EXPIRED state by itself and passes no addresses. It may be
     *     IN_PROGRESS and still return some addresses (when one address family
     *     arrived and is is returned, but the other is still on the way).
     * \todo Should we sort out unreachable addresses as well?
     */
139
    Fetchable::State getAddresses(AddressVector& addresses,
140
        AddressFamily family = ANY_OK, bool expired_ok = false);
141

142
143
144
    /// \brief Return Address that corresponding to the index
    ///
    /// \param index The address index in the address vector
145
146
147
    /// \param family The address family, V4_ONLY or V6_ONLY
    asiolink::IOAddress getAddressAtIndex(size_t index,
        AddressFamily family) const;
148

149
150
151
152
153
    /// \brief Update RTT
    ///
    /// Updates the RTT for a particular address
    ///
    /// \param address Address to update
154
    /// \param rtt New RTT for the address
155
    void setAddressRTT(const asiolink::IOAddress& address, uint32_t rtt);
156

157
158
    /// \brief Update RTT of the address that corresponding to the index
    ///
159
160
    /// Shouldn't probably be used directly. Use corresponding
    /// NameserverAddress.
161
162
    /// \param rtt Round-Trip Time
    /// \param index The address's index in address vector
163
164
165
    /// \param family The address family, V4_ONLY or V6_ONLY
    void updateAddressRTTAtIndex(uint32_t rtt, size_t index,
        AddressFamily family);
166
167
168
169
    /**
     * \short Update RTT of an address.
     *
     * This is similar to updateAddressRTTAtIndex, but you pass the address,
170
171
     * not its index. Passing the index might be unsafe, because the position
     * of the address or the count of addresses may change in time.
172
173
174
175
176
177
178
     *
     * \param rtt Round-Trip Time
     * \param address The address whose RTT should be updated.
     * \param family The address family, V4_ONLY or V6_ONLY
     */
    void updateAddressRTT(uint32_t rtt, const asiolink::IOAddress& address,
        AddressFamily family);
179

180
181
182
183
184
    /// \brief Set Address Unreachable
    ///
    /// Sets the specified address to be unreachable
    ///
    /// \param address Address to update
185
    void setAddressUnreachable(const asiolink::IOAddress& address);
186
187

    /// \return Owner Name of RRset
188
    std::string getName() const {
189
190
191
192
        return name_;
    }

    /// \return Class of RRset
Michal Vaner's avatar
Michal Vaner committed
193
    const isc::dns::RRClass& getClass() const {
194
195
196
        return classCode_;
    }

197
198
199
200
201
    /// \return Hash Key of the Nameserver
    virtual HashKey hashKey() const {
        return HashKey(name_, classCode_);
    }

202
203
    /// \return Hash Key of the Nameserver

204
205
206
207
208
    /// \return Expiration Time of Data
    ///
    /// Returns the expiration time of addresses for this nameserver.  For
    /// simplicity, this quantity is calculated as the minimum expiration time
    /// of the A and AAAA address records.
209
    time_t getExpiration() const {
210
211
212
        return expiration_;
    }

213
214
215
216
    /// \name Obtaining the IP addresses from resolver
    //@{
    /// \short A callback that some information here arrived (or are unavailable).
    struct Callback {
217
        virtual void operator()(boost::shared_ptr<NameserverEntry> self) = 0;
218
219
        /// \short Virtual destructor, so descendants are properly cleaned up
        virtual ~ Callback() {}
220
221
222
223
224
225
226
227
    };

    /**
     * \short Asks the resolver for IP address (or addresses).
     *
     * Adds a callback for given zone when they are ready or the information
     * is found unreachable.
     *
228
229
230
     * If it is not in NOT_ASKED or EXPIRED state, it does not ask the for the
     * IP address again, it just inserts the callback. It is up to the caller
     * not to insert one callback multiple times.
231
     *
Michal Vaner's avatar
Michal Vaner committed
232
     * The callback might be called directly from this function.
233
234
235
     *
     * \param resolver Who to ask.
     * \param callback The callback.
Michal Vaner's avatar
Michal Vaner committed
236
     * \param family Which addresses are interesting to the caller. This does
237
     *     not change which addresses are requested, but the callback might
Michal Vaner's avatar
Michal Vaner committed
238
239
     *     be executed when at last one requested type is available (eg. not
     *     waiting for the other one).
240
241
242
     * \return The state the entry is currently in. It can return UNREACHABLE
     *     even when there are addresses, if there are no addresses for this
     *     family.
243
     */
244
    void askIP(isc::resolve::ResolverInterface* resolver,
245
        boost::shared_ptr<Callback> callback, AddressFamily family);
246
247
    //@}

248
private:
249
    mutable isc::util::locks::recursive_mutex    mutex_;///< Mutex protecting this object
250
    std::string     name_;              ///< Canonical name of the nameserver
Michal Vaner's avatar
Michal Vaner committed
251
    isc::dns::RRClass classCode_;       ///< Class of the nameserver
252
253
254
255
256
257
258
259
260
261
    /**
     * \short Address lists.
     *
     * Only V4_ONLY and V6_ONLY is used, therefore we use the nearest larger
     * value as the size of the array.
     *
     * previous_addresses is kept until the data arrive again on re-fetch and
     * is used to pick up the RTTs from there.
     */
    std::vector<AddressEntry> addresses_[ANY_OK], previous_addresses_[ANY_OK];
262
    time_t          expiration_;        ///< Summary expiration time. 0 = unset
263
264
265
266
    // Do we have some addresses already? Do we expect some to come?
    // These are set after asking for IP, if NOT_ASKED, they are uninitialized
    bool has_address_[ADDR_REQ_MAX], expect_address_[ADDR_REQ_MAX];
    // Callbacks from resolver
267
268
    class ResolverCallback;
    friend class ResolverCallback;
269
270
271
272
273
    // Callbacks inserted into this object
    typedef std::pair<AddressFamily, boost::shared_ptr<Callback> >
        CallbackPair;
    std::vector<CallbackPair> callbacks_;
    /// \short Private version that does the actual asking of one address type
Michal Vaner's avatar
Michal Vaner committed
274
275
    ///
    /// Call unlocked.
276
    void askIP(isc::resolve::ResolverInterface* resolver,
277
        const isc::dns::RRType&, AddressFamily);
278
279
280
281
282
};

}   // namespace dns
}   // namespace isc

283
#endif // NAMESERVER_ENTRY_H