client_list.cc 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. // Copyright (C) 2012 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 "client_list.h"
  15. #include "client.h"
  16. #include "factory.h"
  17. #include <memory>
  18. #include <boost/foreach.hpp>
  19. using namespace isc::data;
  20. using namespace std;
  21. namespace isc {
  22. namespace datasrc {
  23. void
  24. ConfigurableClientList::configure(const Element& config, bool) {
  25. // TODO: Implement the cache
  26. // TODO: Implement recycling from the old configuration.
  27. size_t i(0); // Outside of the try to be able to access it in the catch
  28. try {
  29. vector<DataSourceInfo> new_data_sources;
  30. for (; i < config.size(); ++i) {
  31. // Extract the parameters
  32. const ConstElementPtr dconf(config.get(i));
  33. const ConstElementPtr typeElem(dconf->get("type"));
  34. if (typeElem == ConstElementPtr()) {
  35. isc_throw(ConfigurationError, "Missing the type option in "
  36. "data source no " << i);
  37. }
  38. const string type(typeElem->stringValue());
  39. ConstElementPtr paramConf(dconf->get("params"));
  40. if (paramConf == ConstElementPtr()) {
  41. paramConf.reset(new NullElement());
  42. }
  43. // TODO: Special-case the master files type.
  44. // Ask the factory to create the data source for us
  45. const DataSourcePair ds(this->getDataSourceClient(type,
  46. paramConf));
  47. // And put it into the vector
  48. new_data_sources.push_back(DataSourceInfo(ds.first, ds.second));
  49. }
  50. // If everything is OK up until now, we have the new configuration
  51. // ready. So just put it there and let the old one die when we exit
  52. // the scope.
  53. data_sources_.swap(new_data_sources);
  54. } catch (const TypeError& te) {
  55. isc_throw(ConfigurationError, "Malformed configuration at data source "
  56. "no. " << i << ": " << te.what());
  57. }
  58. }
  59. ClientList::FindResult
  60. ConfigurableClientList::find(const dns::Name& name, bool want_exact_match,
  61. bool) const
  62. {
  63. // Nothing found yet.
  64. //
  65. // We have this class as a temporary storage, as the FindResult can't be
  66. // assigned.
  67. struct MutableResult {
  68. MutableResult() :
  69. datasrc_client(NULL),
  70. matched_labels(0),
  71. matched(false)
  72. {}
  73. DataSourceClient* datasrc_client;
  74. ZoneFinderPtr finder;
  75. uint8_t matched_labels;
  76. bool matched;
  77. operator FindResult() const {
  78. // Conversion to the right result. If we return this, there was
  79. // a partial match at best.
  80. return (FindResult(datasrc_client, finder, false));
  81. }
  82. } candidate;
  83. BOOST_FOREACH(const DataSourceInfo& info, data_sources_) {
  84. // TODO: Once we have support for the caches, consider them too here
  85. // somehow. This would probably get replaced by a function, that
  86. // checks if there's a cache available, if it is, checks the loaded
  87. // zones and zones expected to be in the real data source. If it is
  88. // the cached one, provide the cached one. If it is in the external
  89. // data source, use the datasource and don't provide the finder yet.
  90. const DataSourceClient::FindResult result(
  91. info.data_src_client_->findZone(name));
  92. switch (result.code) {
  93. case result::SUCCESS:
  94. // If we found an exact match, we have no hope to getting
  95. // a better one. Stop right here.
  96. // TODO: In case we have only the datasource and not the finder
  97. // and the need_updater parameter is true, get the zone there.
  98. return (FindResult(info.data_src_client_, result.zone_finder,
  99. true));
  100. case result::PARTIALMATCH:
  101. if (!want_exact_match) {
  102. // In case we have a partial match, check if it is better
  103. // than what we have. If so, replace it.
  104. //
  105. // We don't need the labels at the first partial match,
  106. // we have nothing to compare with. So we don't get it
  107. // (as a performance) and hope we will not need it at all.
  108. const uint8_t labels(candidate.matched ?
  109. result.zone_finder->getOrigin().getLabelCount() : 0);
  110. if (candidate.matched && candidate.matched_labels == 0) {
  111. // But if the hope turns out to be false, we need to
  112. // compute it for the first match anyway.
  113. candidate.matched_labels = candidate.finder->
  114. getOrigin().getLabelCount();
  115. }
  116. if (labels > candidate.matched_labels ||
  117. !candidate.matched) {
  118. // This one is strictly better. Replace it.
  119. candidate.datasrc_client = info.data_src_client_;
  120. candidate.finder = result.zone_finder;
  121. candidate.matched_labels = labels;
  122. candidate.matched = true;
  123. }
  124. }
  125. break;
  126. default:
  127. // Nothing found, nothing to do.
  128. break;
  129. }
  130. }
  131. // TODO: In case we have only the datasource and not the finder
  132. // and the need_updater parameter is true, get the zone there.
  133. // Return the partial match we have. In case we didn't want a partial
  134. // match, this surely contains the original empty result.
  135. return (candidate);
  136. }
  137. // NOTE: This function is not tested, it would be complicated. However, the
  138. // purpose of the function is to provide a very thin wrapper to be able to
  139. // replace the call to DataSourceClientContainer constructor in tests.
  140. ConfigurableClientList::DataSourcePair
  141. ConfigurableClientList::getDataSourceClient(const string& type,
  142. const ConstElementPtr&
  143. configuration)
  144. {
  145. DataSourceClientContainerPtr
  146. container(new DataSourceClientContainer(type, configuration));
  147. return (DataSourcePair(&container->getInstance(), container));
  148. }
  149. }
  150. }