master_loader.cc 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652
  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/rdataclass.h>
  18. #include <dns/rrttl.h>
  19. #include <dns/rrclass.h>
  20. #include <dns/rrtype.h>
  21. #include <dns/rdata.h>
  22. #include <boost/scoped_ptr.hpp>
  23. #include <boost/algorithm/string/predicate.hpp> // for iequals
  24. #include <string>
  25. #include <memory>
  26. #include <vector>
  27. #include <boost/algorithm/string/predicate.hpp> // for iequals
  28. #include <boost/shared_ptr.hpp>
  29. using std::string;
  30. using std::auto_ptr;
  31. using std::vector;
  32. using std::pair;
  33. using boost::algorithm::iequals;
  34. using boost::shared_ptr;
  35. namespace isc {
  36. namespace dns {
  37. namespace {
  38. // An internal exception, used to control the code flow in case of errors.
  39. // It is thrown during the loading and caught later, not to be propagated
  40. // outside of the file.
  41. class InternalException : public isc::Exception {
  42. public:
  43. InternalException(const char* filename, size_t line, const char* what) :
  44. Exception(filename, line, what)
  45. {}
  46. };
  47. } // end unnamed namespace
  48. // cppcheck-suppress noConstructor
  49. class MasterLoader::MasterLoaderImpl {
  50. public:
  51. MasterLoaderImpl(const char* master_file,
  52. const Name& zone_origin,
  53. const RRClass& zone_class,
  54. const MasterLoaderCallbacks& callbacks,
  55. const AddRRCallback& add_callback,
  56. MasterLoader::Options options) :
  57. lexer_(),
  58. zone_origin_(zone_origin),
  59. active_origin_(zone_origin),
  60. zone_class_(zone_class),
  61. callbacks_(callbacks),
  62. add_callback_(add_callback),
  63. options_(options),
  64. master_file_(master_file),
  65. initialized_(false),
  66. ok_(true),
  67. many_errors_((options & MANY_ERRORS) != 0),
  68. previous_name_(false),
  69. complete_(false),
  70. seen_error_(false),
  71. warn_rfc1035_ttl_(true),
  72. rr_count_(0)
  73. {}
  74. void pushSource(const std::string& filename, const Name& current_origin) {
  75. std::string error;
  76. if (!lexer_.pushSource(filename.c_str(), &error)) {
  77. if (initialized_) {
  78. isc_throw(InternalException, error.c_str());
  79. } else {
  80. // Top-level file
  81. reportError("", 0, error);
  82. ok_ = false;
  83. }
  84. }
  85. // Store the current status, so we can recover it upon popSource
  86. include_info_.push_back(IncludeInfo(current_origin, last_name_));
  87. initialized_ = true;
  88. previous_name_ = false;
  89. }
  90. void pushStreamSource(std::istream& stream) {
  91. lexer_.pushSource(stream);
  92. initialized_ = true;
  93. }
  94. bool loadIncremental(size_t count_limit);
  95. size_t getSize() const { return (lexer_.getTotalSourceSize()); }
  96. size_t getPosition() const { return (lexer_.getPosition()); }
  97. private:
  98. void reportError(const std::string& filename, size_t line,
  99. const std::string& reason)
  100. {
  101. seen_error_ = true;
  102. callbacks_.error(filename, line, reason);
  103. if (!many_errors_) {
  104. // In case we don't have the lenient mode, every error is fatal
  105. // and we throw
  106. ok_ = false;
  107. complete_ = true;
  108. isc_throw(MasterLoaderError, reason.c_str());
  109. }
  110. }
  111. bool popSource() {
  112. if (lexer_.getSourceCount() == 1) {
  113. return (false);
  114. }
  115. lexer_.popSource();
  116. // Restore original origin and last seen name
  117. // We move in tandem, there's an extra item included during the
  118. // initialization, so we can never run out of them
  119. assert(!include_info_.empty());
  120. const IncludeInfo& info(include_info_.back());
  121. active_origin_ = info.first;
  122. last_name_ = info.second;
  123. include_info_.pop_back();
  124. previous_name_ = false;
  125. return (true);
  126. }
  127. // Get a string token. Handle it as error if it is not string.
  128. const string getString() {
  129. lexer_.getNextToken(MasterToken::STRING).getString(string_token_);
  130. return (string_token_);
  131. }
  132. MasterToken handleInitialToken();
  133. void doOrigin(bool is_optional) {
  134. // Parse and create the new origin. It is relative to the previous
  135. // one.
  136. const MasterToken&
  137. name_tok(lexer_.getNextToken(MasterToken::QSTRING, is_optional));
  138. if (name_tok.getType() == MasterToken::QSTRING ||
  139. name_tok.getType() == MasterToken::STRING) {
  140. const MasterToken::StringRegion&
  141. name_string(name_tok.getStringRegion());
  142. active_origin_ = Name(name_string.beg, name_string.len,
  143. &active_origin_);
  144. if (name_string.len > 0 &&
  145. name_string.beg[name_string.len - 1] != '.') {
  146. callbacks_.warning(lexer_.getSourceName(),
  147. lexer_.getSourceLine(),
  148. "The new origin is relative, did you really"
  149. " mean " + active_origin_.toText() + "?");
  150. }
  151. } else {
  152. // If it is not optional, we must not get anything but
  153. // a string token.
  154. assert(is_optional);
  155. // We return the newline there. This is because we want to
  156. // behave the same if there is or isn't the name, leaving the
  157. // newline there.
  158. lexer_.ungetToken();
  159. }
  160. }
  161. void doInclude() {
  162. // First, get the filename to include
  163. const string
  164. filename(lexer_.getNextToken(MasterToken::QSTRING).getString());
  165. // There optionally can be an origin, that applies before the include.
  166. // We need to save the currently active origin before calling
  167. // doOrigin(), because it would update active_origin_ while we need
  168. // to pass the active origin before recognizing the new origin to
  169. // pushSource. Note: RFC 1035 is not really clear on this: it reads
  170. // "regardless of changes... within the included file", but the new
  171. // origin is not really specified "within the included file".
  172. // Nevertheless, this behavior is probably more likely to be the
  173. // intent of the RFC, and it's compatible with BIND 9.
  174. const Name current_origin = active_origin_;
  175. doOrigin(true);
  176. pushSource(filename, current_origin);
  177. }
  178. // A helper method for loadIncremental(). It parses part of an RR
  179. // until it finds the RR type field. If TTL or RR class is
  180. // specified before the RR type, it also recognizes and validates
  181. // them. explicit_ttl will be set to true if this method finds a
  182. // valid TTL field.
  183. RRType parseRRParams(bool& explicit_ttl, MasterToken rrparam_token) {
  184. // Find TTL, class and type. Both TTL and class are
  185. // optional and may occur in any order if they exist. TTL
  186. // and class come before type which must exist.
  187. //
  188. // [<TTL>] [<class>] <type> <RDATA>
  189. // [<class>] [<TTL>] <type> <RDATA>
  190. // named-signzone outputs TTL first, so try parsing it in order
  191. // first.
  192. if (setCurrentTTL(rrparam_token.getString())) {
  193. explicit_ttl = true;
  194. rrparam_token = lexer_.getNextToken(MasterToken::STRING);
  195. } else {
  196. // If it's not a TTL here, continue and try again
  197. // after the RR class below.
  198. }
  199. const MaybeRRClass rrclass =
  200. RRClass::createFromText(rrparam_token.getString());
  201. if (rrclass) {
  202. // FIXME: The following code re-parses the rrparam_token to
  203. // make an RRClass instead of using the MaybeRRClass above,
  204. // because some old versions of boost::optional (that we
  205. // still want to support) have a bug (see trac #2593). This
  206. // workaround should be removed at some point in the future.
  207. if (RRClass(rrparam_token.getString()) != zone_class_) {
  208. isc_throw(InternalException, "Class mismatch: " << *rrclass <<
  209. " vs. " << zone_class_);
  210. }
  211. rrparam_token = lexer_.getNextToken(MasterToken::STRING);
  212. }
  213. // If we couldn't parse TTL earlier in the stream (above), try
  214. // again at current location.
  215. if (!explicit_ttl && setCurrentTTL(rrparam_token.getString())) {
  216. explicit_ttl = true;
  217. rrparam_token = lexer_.getNextToken(MasterToken::STRING);
  218. }
  219. // Return the current string token's value as the RRType.
  220. return (RRType(rrparam_token.getString()));
  221. }
  222. // Upper limit check when recognizing a specific TTL value from the
  223. // zone file ($TTL, the RR's TTL field, or the SOA minimum). RFC2181
  224. // Section 8 limits the range of TTL values to 2^31-1 (0x7fffffff),
  225. // and prohibits transmitting a TTL field exceeding this range. We
  226. // guarantee that by limiting the value at the time of zone
  227. // parsing/loading, following what BIND 9 does. Resetting it to 0
  228. // at this point may not be exactly what the RFC states (depending on
  229. // the meaning of 'received'), but the end result would be the same (i.e.,
  230. // the guarantee on transmission). Again, we follow the BIND 9's behavior
  231. // here.
  232. //
  233. // post_parsing is true iff this method is called after parsing the entire
  234. // RR and the lexer is positioned at the next line. It's just for
  235. // calculating the accurate source line when callback is necessary.
  236. void limitTTL(RRTTL& ttl, bool post_parsing) {
  237. if (ttl > RRTTL::MAX_TTL()) {
  238. const size_t src_line = lexer_.getSourceLine() -
  239. (post_parsing ? 1 : 0);
  240. callbacks_.warning(lexer_.getSourceName(), src_line,
  241. "TTL " + ttl.toText() + " > MAXTTL, "
  242. "setting to 0 per RFC2181");
  243. ttl = RRTTL(0);
  244. }
  245. }
  246. // Set/reset the default TTL. This should be from either $TTL or SOA
  247. // minimum TTL (it's the caller's responsibility; this method doesn't
  248. // care about where it comes from). see LimitTTL() for parameter
  249. // post_parsing.
  250. void setDefaultTTL(const RRTTL& ttl, bool post_parsing) {
  251. if (!default_ttl_) {
  252. default_ttl_.reset(new RRTTL(ttl));
  253. } else {
  254. *default_ttl_ = ttl;
  255. }
  256. limitTTL(*default_ttl_, post_parsing);
  257. }
  258. // Try to set/reset the current TTL from candidate TTL text. It's possible
  259. // it does not actually represent a TTL (which is not immediately
  260. // considered an error). Return true iff it's recognized as a valid TTL
  261. // (and only in which case the current TTL is set).
  262. bool setCurrentTTL(const string& ttl_txt) {
  263. // We use the factory version instead of RRTTL constructor as we
  264. // need to expect cases where ttl_txt does not actually represent a TTL
  265. // but an RR class or type.
  266. const MaybeRRTTL maybe_ttl = RRTTL::createFromText(ttl_txt);
  267. if (maybe_ttl) {
  268. current_ttl_ = maybe_ttl;
  269. limitTTL(*current_ttl_, false);
  270. return (true);
  271. }
  272. return (false);
  273. }
  274. // Determine the TTL of the current RR based on the given parsing context.
  275. //
  276. // explicit_ttl is true iff the TTL is explicitly specified for that RR
  277. // (in which case current_ttl_ is set to that TTL).
  278. // rrtype is the type of the current RR, and rdata is its RDATA. They
  279. // only matter if the type is SOA and no available TTL is known. In this
  280. // case the minimum TTL of the SOA will be used as the TTL of that SOA
  281. // and the default TTL for subsequent RRs.
  282. const RRTTL& getCurrentTTL(bool explicit_ttl, const RRType& rrtype,
  283. const rdata::ConstRdataPtr& rdata) {
  284. // We've completed parsing the full of RR, and the lexer is already
  285. // positioned at the next line. If we need to call callback,
  286. // we need to adjust the line number.
  287. const size_t current_line = lexer_.getSourceLine() - 1;
  288. if (!current_ttl_ && !default_ttl_) {
  289. if (rrtype == RRType::SOA()) {
  290. callbacks_.warning(lexer_.getSourceName(), current_line,
  291. "no TTL specified; "
  292. "using SOA MINTTL instead");
  293. const uint32_t ttl_val =
  294. dynamic_cast<const rdata::generic::SOA&>(*rdata).
  295. getMinimum();
  296. setDefaultTTL(RRTTL(ttl_val), true);
  297. current_ttl_ = *default_ttl_;
  298. } else {
  299. // On catching the exception we'll try to reach EOL again,
  300. // so we need to unget it now.
  301. lexer_.ungetToken();
  302. throw InternalException(__FILE__, __LINE__,
  303. "no TTL specified; load rejected");
  304. }
  305. } else if (!explicit_ttl && default_ttl_) {
  306. current_ttl_ = *default_ttl_;
  307. } else if (!explicit_ttl && warn_rfc1035_ttl_) {
  308. // Omitted (class and) TTL values are default to the last
  309. // explicitly stated values (RFC 1035, Sec. 5.1).
  310. callbacks_.warning(lexer_.getSourceName(), current_line,
  311. "using RFC1035 TTL semantics; default to the "
  312. "last explicitly stated TTL");
  313. warn_rfc1035_ttl_ = false; // we only warn about this once
  314. }
  315. assert(current_ttl_);
  316. return (*current_ttl_);
  317. }
  318. void handleDirective(const char* directive, size_t length) {
  319. if (iequals(directive, "INCLUDE")) {
  320. doInclude();
  321. } else if (iequals(directive, "ORIGIN")) {
  322. doOrigin(false);
  323. eatUntilEOL(true);
  324. } else if (iequals(directive, "TTL")) {
  325. setDefaultTTL(RRTTL(getString()), false);
  326. eatUntilEOL(true);
  327. } else {
  328. isc_throw(InternalException, "Unknown directive '" <<
  329. string(directive, directive + length) << "'");
  330. }
  331. }
  332. void eatUntilEOL(bool reportExtra) {
  333. // We want to continue. Try to read until the end of line
  334. for (;;) {
  335. const MasterToken& token(lexer_.getNextToken());
  336. switch (token.getType()) {
  337. case MasterToken::END_OF_FILE:
  338. callbacks_.warning(lexer_.getSourceName(),
  339. lexer_.getSourceLine(),
  340. "File does not end with newline");
  341. // We don't pop here. The End of file will stay there,
  342. // and we'll handle it in the next iteration of
  343. // loadIncremental properly.
  344. return;
  345. case MasterToken::END_OF_LINE:
  346. // Found the end of the line. Good.
  347. return;
  348. default:
  349. // Some other type of token.
  350. if (reportExtra) {
  351. reportExtra = false;
  352. reportError(lexer_.getSourceName(),
  353. lexer_.getSourceLine(),
  354. "Extra tokens at the end of line");
  355. }
  356. break;
  357. }
  358. }
  359. }
  360. private:
  361. MasterLexer lexer_;
  362. const Name zone_origin_;
  363. Name active_origin_; // The origin used during parsing
  364. // (modifiable by $ORIGIN)
  365. shared_ptr<Name> last_name_; // Last seen name (for INITAL_WS handling)
  366. const RRClass zone_class_;
  367. MasterLoaderCallbacks callbacks_;
  368. const AddRRCallback add_callback_;
  369. boost::scoped_ptr<RRTTL> default_ttl_; // Default TTL of RRs used when
  370. // unspecified. If NULL no default
  371. // is known.
  372. MaybeRRTTL current_ttl_; // The TTL used most recently. Initially unset.
  373. // Once set always stores a valid RRTTL.
  374. const MasterLoader::Options options_;
  375. const std::string master_file_;
  376. std::string string_token_;
  377. bool initialized_;
  378. bool ok_; // Is it OK to continue loading?
  379. const bool many_errors_; // Are many errors allowed (or should we abort
  380. // on the first)
  381. // Some info about the outer files from which we include.
  382. // The first one is current origin, the second is the last seen name
  383. // in that file.
  384. typedef pair<Name, shared_ptr<Name> > IncludeInfo;
  385. vector<IncludeInfo> include_info_;
  386. bool previous_name_; // True if there was a previous name in this file
  387. // (false at the beginning or after an $INCLUDE line)
  388. public:
  389. bool complete_; // All work done.
  390. bool seen_error_; // Was there at least one error during the
  391. // load?
  392. bool warn_rfc1035_ttl_; // should warn if implicit TTL determination
  393. // from the previous RR is used.
  394. size_t rr_count_; // number of RRs successfully loaded
  395. };
  396. // A helper method of loadIncremental, parsing the first token of a new line.
  397. // If it looks like an RR, detect its owner name and return a string token for
  398. // the next field of the RR.
  399. // Otherwise, return either END_OF_LINE or END_OF_FILE token depending on
  400. // whether the loader continues to the next line or completes the load,
  401. // respectively. Other corner cases including $-directive handling is done
  402. // here.
  403. // For unexpected errors, it throws an exception, which will be handled in
  404. // loadIncremental.
  405. MasterToken
  406. MasterLoader::MasterLoaderImpl::handleInitialToken() {
  407. const MasterToken& initial_token =
  408. lexer_.getNextToken(MasterLexer::QSTRING | MasterLexer::INITIAL_WS);
  409. // The most likely case is INITIAL_WS, and then string/qstring. We
  410. // handle them first.
  411. if (initial_token.getType() == MasterToken::INITIAL_WS) {
  412. const MasterToken& next_token = lexer_.getNextToken();
  413. if (next_token.getType() == MasterToken::END_OF_LINE) {
  414. return (next_token); // blank line
  415. } else if (next_token.getType() == MasterToken::END_OF_FILE) {
  416. lexer_.ungetToken(); // handle it in the next iteration.
  417. eatUntilEOL(true); // effectively warn about the unexpected EOF.
  418. return (MasterToken(MasterToken::END_OF_LINE));
  419. }
  420. // This means the same name as previous.
  421. if (last_name_.get() == NULL) {
  422. isc_throw(InternalException, "No previous name to use in "
  423. "place of initial whitespace");
  424. } else if (!previous_name_) {
  425. callbacks_.warning(lexer_.getSourceName(), lexer_.getSourceLine(),
  426. "Owner name omitted around $INCLUDE, the result "
  427. "might not be as expected");
  428. }
  429. return (next_token);
  430. } else if (initial_token.getType() == MasterToken::STRING ||
  431. initial_token.getType() == MasterToken::QSTRING) {
  432. // If it is name (or directive), handle it.
  433. const MasterToken::StringRegion&
  434. name_string(initial_token.getStringRegion());
  435. if (name_string.len > 0 && name_string.beg[0] == '$') {
  436. // This should have either thrown (and the error handler
  437. // will read up until the end of line) or read until the
  438. // end of line.
  439. // Exclude the $ from the string on this point.
  440. handleDirective(name_string.beg + 1, name_string.len - 1);
  441. // So, get to the next line, there's nothing more interesting
  442. // in this one.
  443. return (MasterToken(MasterToken::END_OF_LINE));
  444. }
  445. // This should be an RR, starting with an owner name. Construct the
  446. // name, and some string token should follow.
  447. last_name_.reset(new Name(name_string.beg, name_string.len,
  448. &active_origin_));
  449. previous_name_ = true;
  450. return (lexer_.getNextToken(MasterToken::STRING));
  451. }
  452. switch (initial_token.getType()) { // handle less common cases
  453. case MasterToken::END_OF_FILE:
  454. if (!popSource()) {
  455. return (initial_token);
  456. } else {
  457. // We try to read a token from the popped source
  458. // So continue to the next line of that source, but first, make
  459. // sure the source is at EOL
  460. eatUntilEOL(true);
  461. return (MasterToken(MasterToken::END_OF_LINE));
  462. }
  463. case MasterToken::END_OF_LINE:
  464. return (initial_token); // empty line
  465. case MasterToken::ERROR:
  466. // Error token here.
  467. isc_throw(InternalException, initial_token.getErrorText());
  468. default:
  469. // Some other token (what could that be?)
  470. isc_throw(InternalException, "Parser got confused (unexpected "
  471. "token " << initial_token.getType() << ")");
  472. }
  473. }
  474. bool
  475. MasterLoader::MasterLoaderImpl::loadIncremental(size_t count_limit) {
  476. if (count_limit == 0) {
  477. isc_throw(isc::InvalidParameter, "Count limit set to 0");
  478. }
  479. if (complete_) {
  480. isc_throw(isc::InvalidOperation,
  481. "Trying to load when already loaded");
  482. }
  483. if (!initialized_) {
  484. pushSource(master_file_, active_origin_);
  485. }
  486. size_t count = 0;
  487. while (ok_ && count < count_limit) {
  488. try {
  489. const MasterToken next_token = handleInitialToken();
  490. if (next_token.getType() == MasterToken::END_OF_FILE) {
  491. return (true); // we are done
  492. } else if (next_token.getType() == MasterToken::END_OF_LINE) {
  493. continue; // nothing more to do in this line
  494. }
  495. // We are going to parse an RR, have known the owner name,
  496. // and are now seeing the next string token in the rest of the RR.
  497. assert(next_token.getType() == MasterToken::STRING);
  498. bool explicit_ttl = false;
  499. const RRType rrtype = parseRRParams(explicit_ttl, next_token);
  500. // TODO: Check if it is SOA, it should be at the origin.
  501. const rdata::RdataPtr rdata =
  502. rdata::createRdata(rrtype, zone_class_, lexer_,
  503. &active_origin_, options_, callbacks_);
  504. // In case we get NULL, it means there was error creating
  505. // the Rdata. The errors should have been reported by
  506. // callbacks_ already. We need to decide if we want to continue
  507. // or not.
  508. if (rdata) {
  509. add_callback_(*last_name_, zone_class_, rrtype,
  510. getCurrentTTL(explicit_ttl, rrtype, rdata),
  511. rdata);
  512. // Good, we loaded another one
  513. ++count;
  514. ++rr_count_;
  515. } else {
  516. seen_error_ = true;
  517. if (!many_errors_) {
  518. ok_ = false;
  519. complete_ = true;
  520. // We don't have the exact error here, but it was reported
  521. // by the error callback.
  522. isc_throw(MasterLoaderError, "Invalid RR data");
  523. }
  524. }
  525. } catch (const MasterLoaderError&) {
  526. // This is a hack. We exclude the MasterLoaderError from the
  527. // below case. Once we restrict the below to some smaller
  528. // exception, we should remove this.
  529. throw;
  530. } catch (const isc::Exception& e) {
  531. // TODO: Once we do #2518, catch only the DNSTextError here,
  532. // not isc::Exception. The rest should be just simply
  533. // propagated.
  534. reportError(lexer_.getSourceName(), lexer_.getSourceLine(),
  535. e.what());
  536. eatUntilEOL(false);
  537. }
  538. }
  539. // When there was a fatal error and ok is false, we say we are done.
  540. return (!ok_);
  541. }
  542. MasterLoader::MasterLoader(const char* master_file,
  543. const Name& zone_origin,
  544. const RRClass& zone_class,
  545. const MasterLoaderCallbacks& callbacks,
  546. const AddRRCallback& add_callback,
  547. Options options)
  548. {
  549. if (add_callback.empty()) {
  550. isc_throw(isc::InvalidParameter, "Empty add RR callback");
  551. }
  552. impl_ = new MasterLoaderImpl(master_file, zone_origin,
  553. zone_class, callbacks, add_callback, options);
  554. }
  555. MasterLoader::MasterLoader(std::istream& stream,
  556. const Name& zone_origin,
  557. const RRClass& zone_class,
  558. const MasterLoaderCallbacks& callbacks,
  559. const AddRRCallback& add_callback,
  560. Options options)
  561. {
  562. if (add_callback.empty()) {
  563. isc_throw(isc::InvalidParameter, "Empty add RR callback");
  564. }
  565. auto_ptr<MasterLoaderImpl> impl(new MasterLoaderImpl("", zone_origin,
  566. zone_class, callbacks,
  567. add_callback,
  568. options));
  569. impl->pushStreamSource(stream);
  570. impl_ = impl.release();
  571. }
  572. MasterLoader::~MasterLoader() {
  573. delete impl_;
  574. }
  575. bool
  576. MasterLoader::loadIncremental(size_t count_limit) {
  577. const bool result = impl_->loadIncremental(count_limit);
  578. impl_->complete_ = result;
  579. return (result);
  580. }
  581. bool
  582. MasterLoader::loadedSucessfully() const {
  583. return (impl_->complete_ && !impl_->seen_error_);
  584. }
  585. size_t
  586. MasterLoader::getSize() const {
  587. return (impl_->getSize());
  588. }
  589. size_t
  590. MasterLoader::getPosition() const {
  591. return (impl_->getPosition());
  592. }
  593. } // end namespace dns
  594. } // end namespace isc