master_loader.cc 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  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 <dns/master_loader.h>
  15. #include <dns/master_lexer.h>
  16. #include <dns/name.h>
  17. #include <dns/rrttl.h>
  18. #include <dns/rrclass.h>
  19. #include <dns/rrtype.h>
  20. #include <dns/rdata.h>
  21. using std::string;
  22. namespace isc {
  23. namespace dns {
  24. class MasterLoader::MasterLoaderImpl {
  25. public:
  26. MasterLoaderImpl(const char* master_file,
  27. const Name& zone_origin,
  28. const RRClass& zone_class,
  29. const MasterLoaderCallbacks& callbacks,
  30. const AddRRCallback& add_callback,
  31. MasterLoader::Options options) :
  32. lexer_(),
  33. zone_origin_(zone_origin),
  34. zone_class_(zone_class),
  35. callbacks_(callbacks),
  36. add_callback_(add_callback),
  37. options_(options),
  38. master_file_(master_file),
  39. initialized_(false),
  40. ok_(true),
  41. complete_(false)
  42. {}
  43. void pushSource(const std::string& filename) {
  44. std::string error;
  45. if (!lexer_.pushSource(filename.c_str(), &error)) {
  46. ok_ = false;
  47. callbacks_.error("", 0, error);
  48. }
  49. }
  50. // Get a string token. Handle it as error if it is not string.
  51. const string getString() {
  52. return (lexer_.getNextToken(MasterToken::QSTRING).getString());
  53. }
  54. bool loadIncremental(size_t count_limit) {
  55. if (complete_) {
  56. isc_throw(isc::InvalidOperation,
  57. "Trying to load when already loaded");
  58. }
  59. if (!initialized_) {
  60. pushSource(master_file_);
  61. initialized_ = true;
  62. }
  63. size_t count = 0;
  64. while (ok_ && count < count_limit) {
  65. try {
  66. // Skip all EOLNs (empty lines) and finish on EOF
  67. bool empty = true;
  68. do {
  69. const MasterToken& empty_token(lexer_.getNextToken());
  70. if (empty_token.getType() == MasterToken::END_OF_FILE) {
  71. // TODO: Check if this is the last source, possibly pop
  72. return (true);
  73. }
  74. empty = empty_token.getType() == MasterToken::END_OF_LINE;
  75. } while (empty);
  76. // Return the last token, as it was not empty
  77. lexer_.ungetToken();
  78. const MasterToken::StringRegion
  79. name_string(lexer_.getNextToken(MasterToken::QSTRING).
  80. getStringRegion());
  81. // TODO $ handling
  82. const Name name(name_string.beg, name_string.len,
  83. &zone_origin_);
  84. // TODO: Some more flexibility. We don't allow omitting
  85. // anything yet
  86. // The parameters
  87. const RRTTL ttl(getString());
  88. const RRClass rrclass(getString());
  89. const RRType rrtype(getString());
  90. // TODO: Some more validation?
  91. if (rrclass != zone_class_) {
  92. // It doesn't really matter much what type of exception
  93. // we throw, we catch it just below.
  94. isc_throw(isc::BadValue, "Class mismatch: " << rrclass <<
  95. "vs. " << zone_class_);
  96. }
  97. const rdata::RdataPtr data(rdata::createRdata(rrtype, rrclass,
  98. lexer_,
  99. &zone_origin_,
  100. options_,
  101. callbacks_));
  102. // In case we get NULL, it means there was error creating
  103. // the Rdata. The errors should have been reported by
  104. // callbacks_ already. We need to decide if we want to continue
  105. // or not.
  106. if (data != rdata::RdataPtr()) {
  107. add_callback_(name, rrclass, rrtype, ttl, data);
  108. // Good, we loaded another one
  109. ++count;
  110. } else if ((options_ & MANY_ERRORS) == 0) {
  111. return (true);
  112. }
  113. } catch (const isc::Exception& e) {
  114. // TODO: Do we want to list expected exceptions here instead?
  115. callbacks_.error(lexer_.getSourceName(),
  116. lexer_.getSourceLine(),
  117. e.what());
  118. if ((options_ & MANY_ERRORS) != 0) {
  119. // We want to continue. Try to read until the end of line
  120. bool end = false;
  121. do {
  122. const MasterToken& token(lexer_.getNextToken());
  123. switch (token.getType()) {
  124. case MasterToken::END_OF_FILE:
  125. // TODO: Try pop in case this is not the only
  126. // source
  127. return (true);
  128. case MasterToken::END_OF_LINE:
  129. end = true;
  130. break;
  131. default:
  132. // Do nothing. This is just to make compiler
  133. // happy
  134. break;
  135. }
  136. } while (!end);
  137. } else {
  138. // We abort on first error. We are therefore done.
  139. return (true);
  140. }
  141. }
  142. }
  143. // When there was a fatal error and ok is false, we say we are done.
  144. return (!ok_);
  145. }
  146. private:
  147. MasterLexer lexer_;
  148. const Name zone_origin_;
  149. const RRClass zone_class_;
  150. MasterLoaderCallbacks callbacks_;
  151. AddRRCallback add_callback_;
  152. MasterLoader::Options options_;
  153. const std::string master_file_;
  154. bool initialized_;
  155. bool ok_;
  156. public:
  157. bool complete_;
  158. };
  159. MasterLoader::MasterLoader(const char* master_file,
  160. const Name& zone_origin,
  161. const RRClass& zone_class,
  162. const MasterLoaderCallbacks& callbacks,
  163. const AddRRCallback& add_callback,
  164. Options options)
  165. {
  166. if (add_callback.empty()) {
  167. isc_throw(isc::InvalidParameter, "Empty add RR callback");
  168. }
  169. impl_ = new MasterLoaderImpl(master_file, zone_origin,
  170. zone_class, callbacks, add_callback, options);
  171. }
  172. MasterLoader::~MasterLoader() {
  173. delete impl_;
  174. }
  175. bool
  176. MasterLoader::loadIncremental(size_t count_limit) {
  177. const bool result = impl_->loadIncremental(count_limit);
  178. impl_->complete_ = result;
  179. return (result);
  180. }
  181. } // end namespace dns
  182. } // end namespace isc