nameserver_entry.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. // Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. // $Id$
  15. #include <config.h>
  16. #include <algorithm>
  17. #include <functional>
  18. #include <cassert>
  19. #include <iostream>
  20. #include <boost/bind.hpp>
  21. #include <boost/foreach.hpp>
  22. #include <ctype.h>
  23. #include <strings.h>
  24. #include <config.h>
  25. #include <exceptions/exceptions.h>
  26. #include <dns/name.h>
  27. #include <dns/rrclass.h>
  28. #include <dns/rrttl.h>
  29. #include <dns/question.h>
  30. #include "address_entry.h"
  31. #include "nameserver_address.h"
  32. #include "nameserver_entry.h"
  33. #include "resolver_interface.h"
  34. using namespace asiolink;
  35. using namespace isc::nsas;
  36. using namespace isc::dns;
  37. using namespace std;
  38. namespace isc {
  39. namespace nsas {
  40. namespace {
  41. // Just shorter type alias
  42. typedef boost::recursive_mutex::scoped_lock Lock;
  43. }
  44. // Returns the list of addresses matching the given family
  45. Fetchable::State
  46. NameserverEntry::getAddresses(AddressVector& addresses,
  47. AddressFamily family, bool expired_ok)
  48. {
  49. Lock lock(mutex_);
  50. // Check TTL
  51. time_t now(time(NULL));
  52. // We take = as well, so we catch TTL 0 correctly
  53. // expiration_ == 0 means not set, the reason is we are UNREACHABLE or
  54. // NOT_ASKED or IN_PROGRESS
  55. if (getState() != NOT_ASKED && expiration_ && expiration_ <= now) {
  56. setState(EXPIRED);
  57. }
  58. if (getState() == EXPIRED && !expired_ok) {
  59. return EXPIRED;
  60. }
  61. switch (getState()) {
  62. case IN_PROGRESS:
  63. /*
  64. * Did we receive the address already?
  65. *
  66. * We might have already received the addresses for this family
  67. * and still wait for the other (in which case has_address_[family]
  68. * will be true). We might already received a negative answer,
  69. * in which case expect_address_[family] is false and
  70. * has_address_[family] is false as well.
  71. */
  72. if (!has_address_[family] && expect_address_[family]) {
  73. return IN_PROGRESS;
  74. }
  75. // If we do not expect the address, then fall trough to READY
  76. case EXPIRED: // If expired_ok, we pretend to be ready
  77. case READY:
  78. if (!has_address_[family]) {
  79. return UNREACHABLE;
  80. }
  81. break; // OK, we give some answers
  82. case NOT_ASKED:
  83. case UNREACHABLE:
  84. // Reject giving any data
  85. return (getState());
  86. }
  87. boost::shared_ptr<NameserverEntry> self(shared_from_this());
  88. // If any address is OK, just pass everything we have
  89. if (family == ANY_OK) {
  90. BOOST_FOREACH(const AddressEntry& entry, addresses_[V6_ONLY]) {
  91. addresses.push_back(NameserverAddress(self, entry, V6_ONLY));
  92. }
  93. BOOST_FOREACH(const AddressEntry& entry, addresses_[V4_ONLY]) {
  94. addresses.push_back(NameserverAddress(self, entry, V4_ONLY));
  95. }
  96. } else {
  97. BOOST_FOREACH(const AddressEntry& entry, addresses_[family]) {
  98. addresses.push_back(NameserverAddress(self, entry, family));
  99. }
  100. }
  101. if (getState() == EXPIRED && expired_ok) {
  102. return READY;
  103. }
  104. return getState();
  105. }
  106. // Return the address corresponding to the family
  107. asiolink::IOAddress
  108. NameserverEntry::getAddressAtIndex(size_t index, AddressFamily family) const {
  109. Lock lock(mutex_);
  110. assert(index < addresses_[family].size());
  111. return (addresses_[family][index].getAddress());
  112. }
  113. // Set the address RTT to a specific value
  114. void
  115. NameserverEntry::setAddressRTT(const IOAddress& address, uint32_t rtt) {
  116. Lock lock(mutex_);
  117. // Search through the list of addresses for a match
  118. AddressFamily family(V4_ONLY);
  119. for (;;) {
  120. BOOST_FOREACH(AddressEntry& entry, addresses_[family]) {
  121. if (entry.getAddress().equal(address)) {
  122. entry.setRTT(rtt);
  123. return;
  124. }
  125. }
  126. // Hack. C++ does not allow ++ on enums, enumerating trough them is pain
  127. switch (family) {
  128. case V4_ONLY: family = V6_ONLY; break;
  129. default: return;
  130. }
  131. }
  132. }
  133. // Update the address's rtt
  134. #define UPDATE_RTT_ALPHA 0.7
  135. void
  136. NameserverEntry::updateAddressRTTAtIndex(uint32_t rtt, size_t index,
  137. AddressFamily family)
  138. {
  139. Lock lock(mutex_);
  140. //make sure it is a valid index
  141. if(index >= addresses_[family].size()) return;
  142. // Smoothly update the rtt
  143. // The algorithm is as the same as bind8/bind9:
  144. // new_rtt = old_rtt * alpha + new_rtt * (1 - alpha), where alpha is a float number in [0, 1.0]
  145. // The default value for alpha is 0.7
  146. uint32_t old_rtt = addresses_[family][index].getRTT();
  147. uint32_t new_rtt = (uint32_t)(old_rtt * UPDATE_RTT_ALPHA + rtt *
  148. (1 - UPDATE_RTT_ALPHA));
  149. addresses_[family][index].setRTT(new_rtt);
  150. }
  151. void
  152. NameserverEntry::updateAddressRTT(uint32_t rtt,
  153. const asiolink::IOAddress& address, AddressFamily family)
  154. {
  155. Lock lock(mutex_);
  156. for (size_t i(0); i < addresses_[family].size(); ++ i) {
  157. if (addresses_[family][i].getAddress().equal(address)) {
  158. updateAddressRTTAtIndex(rtt, i, family);
  159. return;
  160. }
  161. }
  162. }
  163. // Sets the address to be unreachable
  164. void
  165. NameserverEntry::setAddressUnreachable(const IOAddress& address) {
  166. setAddressRTT(address, AddressEntry::UNREACHABLE);
  167. }
  168. /**
  169. * \short A callback into the resolver.
  170. *
  171. * Whenever we ask the resolver something, this is created and the answer is
  172. * fed back trough this. It holds a shared pointer to the entry so it is not
  173. * destroyed too soon.
  174. */
  175. class NameserverEntry::ResolverCallback : public ResolverInterface::Callback {
  176. public:
  177. ResolverCallback(boost::shared_ptr<NameserverEntry> entry,
  178. AddressFamily family, const RRType& type) :
  179. entry_(entry),
  180. family_(family),
  181. type_(type)
  182. { }
  183. /**
  184. * \short We received the address successfully.
  185. *
  186. * This extracts the addresses out from the response and puts them
  187. * inside the entry. It tries to reuse the address entries from before (if there were any), to keep their RTTs.
  188. */
  189. virtual void success(const boost::shared_ptr<AbstractRRset>& response) {
  190. time_t now = time(NULL);
  191. Lock lock(entry_->mutex_);
  192. vector<AddressEntry> entries;
  193. if (response->getType() != type_ ||
  194. response->getClass() != RRClass(entry_->getClass()))
  195. {
  196. // TODO Log we got answer of different type
  197. failureInternal(lock);
  198. return;
  199. }
  200. for (RdataIteratorPtr i(response->getRdataIterator());
  201. !i->isLast(); i->next())
  202. {
  203. // Try to find the original value and reuse it
  204. string address(i->getCurrent().toText());
  205. AddressEntry *found(NULL);
  206. BOOST_FOREACH(AddressEntry& entry,
  207. entry_->previous_addresses_[family_])
  208. {
  209. if (entry.getAddress().toText() == address) {
  210. // Good, found it.
  211. found = &entry;
  212. break;
  213. }
  214. }
  215. // If we found it, use it. If not, create a new one.
  216. entries.push_back(found ? *found : AddressEntry(IOAddress(
  217. i->getCurrent().toText()), 1));
  218. }
  219. // We no longer need the previous set of addresses, we have
  220. // the current ones now.
  221. entry_->previous_addresses_[family_].clear();
  222. if (entries.empty()) {
  223. // No data there, count it as a failure
  224. failureInternal(lock);
  225. } else {
  226. // We received the data, so mark it
  227. entry_->expect_address_[family_] = false;
  228. entry_->expect_address_[ANY_OK] =
  229. entry_->expect_address_[V4_ONLY] ||
  230. entry_->expect_address_[V6_ONLY];
  231. // Everything is here (all address families)
  232. if (!entry_->expect_address_[ANY_OK]) {
  233. entry_->setState(READY);
  234. }
  235. // We have some address
  236. entry_->has_address_[ANY_OK] =
  237. entry_->has_address_[family_] = true;
  238. // Insert the entries inside
  239. entry_->addresses_[family_].swap(entries);
  240. // Update the expiration time. If it is 0, it means we
  241. // did not set it yet, so reset
  242. time_t expiration(now + response->getTTL().getValue());
  243. if (entry_->expiration_) {
  244. // We expire at the time first address expires
  245. entry_->expiration_ = min(entry_->expiration_, expiration);
  246. } else {
  247. // We have no expiration time set, use this one
  248. entry_->expiration_ = expiration;
  249. }
  250. // Run the right callbacks
  251. dispatchCallbacks(lock);
  252. }
  253. }
  254. /**
  255. * \short The resolver failed to retrieve the data.
  256. *
  257. * So mark the current address family as unreachable.
  258. */
  259. virtual void failure() {
  260. Lock lock(entry_->mutex_);
  261. failureInternal(lock);
  262. }
  263. private:
  264. boost::shared_ptr<NameserverEntry> entry_;
  265. AddressFamily family_;
  266. RRType type_;
  267. // Dispatches all relevant callbacks. Keeps lock unlocked afterwards.
  268. // TODO: We might want to use recursive lock and get rid of this
  269. void dispatchCallbacks(Lock& lock)
  270. {
  271. // We dispatch ANY addresses if there is at last one address or
  272. // there's no chance we'll get some in future
  273. bool dispatch_any = entry_->has_address_[ANY_OK] ||
  274. !entry_->expect_address_[ANY_OK];
  275. // Sort out the callbacks we want
  276. vector<CallbackPair> keep;
  277. vector<boost::shared_ptr<NameserverEntry::Callback> > dispatch;
  278. BOOST_FOREACH(const CallbackPair &callback, entry_->callbacks_)
  279. {
  280. if (callback.first == family_ || (dispatch_any &&
  281. callback.first == ANY_OK))
  282. {
  283. dispatch.push_back(callback.second);
  284. } else {
  285. keep.push_back(callback);
  286. }
  287. }
  288. // Put there only the ones that we do not want, drop the rest
  289. keep.swap(entry_->callbacks_);
  290. keep.clear();
  291. // We can't keep the lock while we execute callbacks
  292. lock.unlock();
  293. // Run all the callbacks
  294. /*
  295. * FIXME: This is not completely exception safe. If there's an
  296. * exception in a callback, we lose the rest of them.
  297. */
  298. BOOST_FOREACH(const boost::shared_ptr<NameserverEntry::Callback>&
  299. callback, dispatch)
  300. {
  301. (*callback)(entry_);
  302. }
  303. }
  304. // Handle a failure to optain data. Dispatches callbacks and leaves
  305. // lock unlocked
  306. void failureInternal(Lock &lock) {
  307. // Set state of the addresses
  308. entry_->expect_address_[family_] = false;
  309. entry_->expect_address_[ANY_OK] =
  310. entry_->expect_address_[V4_ONLY] ||
  311. entry_->expect_address_[V6_ONLY];
  312. // When we do not expect any more addresses, decide the state
  313. if (!entry_->expect_address_[ANY_OK]) {
  314. if (entry_->has_address_[ANY_OK]) {
  315. // We have at last one kind of address, so OK
  316. entry_->setState(READY);
  317. } else {
  318. // No addresses :-(
  319. entry_->setState(UNREACHABLE);
  320. }
  321. }
  322. // Drop the previous addresses, no use of them now
  323. entry_->previous_addresses_[family_].clear();
  324. // Dispatch any relevant callbacks
  325. dispatchCallbacks(lock);
  326. }
  327. };
  328. void
  329. NameserverEntry::askIP(boost::shared_ptr<ResolverInterface> resolver,
  330. const RRType& type, AddressFamily family)
  331. {
  332. QuestionPtr question(new Question(Name(getName()), RRClass(getClass()),
  333. type));
  334. boost::shared_ptr<ResolverCallback> callback(new ResolverCallback(
  335. shared_from_this(), family, type));
  336. resolver->resolve(question, callback);
  337. }
  338. void
  339. NameserverEntry::askIP(boost::shared_ptr<ResolverInterface> resolver,
  340. boost::shared_ptr<Callback> callback, AddressFamily family)
  341. {
  342. Lock lock(mutex_);
  343. if (getState() == EXPIRED || getState() == NOT_ASKED) {
  344. // We will request the addresses
  345. // Set internal state first
  346. // We store the old addresses so we can pick their RTT when
  347. // we get the same addresses again (most probably)
  348. previous_addresses_[V4_ONLY].clear();
  349. previous_addresses_[V6_ONLY].clear();
  350. addresses_[V4_ONLY].swap(previous_addresses_[V4_ONLY]);
  351. addresses_[V6_ONLY].swap(previous_addresses_[V6_ONLY]);
  352. setState(IN_PROGRESS);
  353. has_address_[V4_ONLY] = has_address_[V6_ONLY] = has_address_[ANY_OK] =
  354. false;
  355. expect_address_[V4_ONLY] = expect_address_[V6_ONLY] =
  356. expect_address_[ANY_OK] = true;
  357. expiration_ = 0;
  358. // Store the callback
  359. callbacks_.push_back(CallbackPair(family, callback));
  360. // Ask for both types of addresses
  361. // We are unlocked here, as the callback from that might want to lock
  362. lock.unlock();
  363. askIP(resolver, RRType::A(), V4_ONLY);
  364. askIP(resolver, RRType::AAAA(), V6_ONLY);
  365. // Make sure we end the routine when we are not locked
  366. return;
  367. } else {
  368. // We already asked. Do we expect this address type still to come?
  369. if (!expect_address_[family]) {
  370. // We do not expect it to come, dispatch right away
  371. lock.unlock();
  372. (*callback)(shared_from_this());
  373. return;
  374. } else {
  375. // It will come in future, store the callback until then
  376. callbacks_.push_back(CallbackPair(family, callback));
  377. }
  378. }
  379. }
  380. } // namespace dns
  381. } // namespace isc