nameserver_entry.cc 17 KB

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