rrparamregistry-placeholder.cc 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596
  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. #include <cassert>
  15. #include <algorithm>
  16. #include <cctype>
  17. #include <functional>
  18. #include <map>
  19. #include <string>
  20. #include <sstream>
  21. #include <utility>
  22. #include <stdint.h>
  23. #include <boost/shared_ptr.hpp>
  24. #include <exceptions/exceptions.h>
  25. #include <dns/rrparamregistry.h>
  26. #include <dns/rrclass.h>
  27. #include <dns/rrtype.h>
  28. #include <dns/rdata.h>
  29. #include <dns/rdataclass.h>
  30. using namespace std;
  31. using namespace boost;
  32. using namespace isc::util;
  33. using namespace isc::dns::rdata;
  34. namespace isc {
  35. namespace dns {
  36. namespace rdata {
  37. RdataPtr
  38. AbstractRdataFactory::create(MasterLexer& lexer, const Name*,
  39. MasterLoader::Options,
  40. MasterLoaderCallbacks&) const
  41. {
  42. std::string s;
  43. while (true) {
  44. const MasterToken& token = lexer.getNextToken();
  45. if ((token.getType() == MasterToken::END_OF_FILE) ||
  46. (token.getType() == MasterToken::END_OF_LINE)) {
  47. break;
  48. }
  49. if (!s.empty()) {
  50. s += " ";
  51. }
  52. s += token.getString();
  53. }
  54. return (create(s));
  55. }
  56. } // end of namespace isc::dns::rdata
  57. namespace {
  58. ///
  59. /// The following function and class are a helper to define case-insensitive
  60. /// equivalence relationship on strings. They are used in the mapping
  61. /// containers below.
  62. ///
  63. bool
  64. CICharLess(char c1, char c2) {
  65. return (tolower(static_cast<unsigned char>(c1)) <
  66. tolower(static_cast<unsigned char>(c2)));
  67. }
  68. struct CIStringLess :
  69. public binary_function<string, string, bool>
  70. {
  71. bool operator()(const string& s1, const string& s2) const
  72. {
  73. return (lexicographical_compare(s1.begin(), s1.end(),
  74. s2.begin(), s2.end(), CICharLess));
  75. }
  76. };
  77. struct RRTypeParam {
  78. RRTypeParam(const string& code_string, uint16_t code) :
  79. code_string_(code_string), code_(code) {}
  80. string code_string_;
  81. uint16_t code_;
  82. /// magic constants
  83. static const unsigned int MAX_CODE = 0xffff;
  84. static const string& UNKNOWN_PREFIX();
  85. static size_t UNKNOWN_PREFIXLEN();
  86. static const string& UNKNOWN_MAX();
  87. static size_t UNKNOWN_MAXLEN();
  88. };
  89. typedef boost::shared_ptr<RRTypeParam> RRTypeParamPtr;
  90. typedef map<string, RRTypeParamPtr, CIStringLess> StrRRTypeMap;
  91. typedef map<uint16_t, RRTypeParamPtr> CodeRRTypeMap;
  92. inline const string&
  93. RRTypeParam::UNKNOWN_PREFIX() {
  94. static const string p("TYPE");
  95. return (p);
  96. }
  97. inline size_t
  98. RRTypeParam::UNKNOWN_PREFIXLEN() {
  99. static size_t plen = UNKNOWN_PREFIX().size();
  100. return (plen);
  101. }
  102. inline const string&
  103. RRTypeParam::UNKNOWN_MAX() {
  104. static const string p("TYPE65535");
  105. return (p);
  106. }
  107. inline size_t
  108. RRTypeParam::UNKNOWN_MAXLEN() {
  109. static size_t plen = UNKNOWN_MAX().size();
  110. return (plen);
  111. }
  112. struct RRClassParam {
  113. RRClassParam(const string& code_string, uint16_t code) :
  114. code_string_(code_string), code_(code) {}
  115. string code_string_;
  116. uint16_t code_;
  117. /// magic constants
  118. static const unsigned int MAX_CODE = 0xffff;
  119. static const string& UNKNOWN_PREFIX();
  120. static size_t UNKNOWN_PREFIXLEN();
  121. static const string& UNKNOWN_MAX();
  122. static size_t UNKNOWN_MAXLEN();
  123. };
  124. typedef boost::shared_ptr<RRClassParam> RRClassParamPtr;
  125. typedef map<string, RRClassParamPtr, CIStringLess> StrRRClassMap;
  126. typedef map<uint16_t, RRClassParamPtr> CodeRRClassMap;
  127. inline const string&
  128. RRClassParam::UNKNOWN_PREFIX() {
  129. static const string p("CLASS");
  130. return (p);
  131. }
  132. inline size_t
  133. RRClassParam::UNKNOWN_PREFIXLEN() {
  134. static size_t plen = UNKNOWN_PREFIX().size();
  135. return (plen);
  136. }
  137. inline const string&
  138. RRClassParam::UNKNOWN_MAX() {
  139. static const string p("CLASS65535");
  140. return (p);
  141. }
  142. inline size_t
  143. RRClassParam::UNKNOWN_MAXLEN() {
  144. static size_t plen = UNKNOWN_MAX().size();
  145. return (plen);
  146. }
  147. } // end of anonymous namespace
  148. /// Note: the element ordering in the type/class pair is intentional.
  149. /// The standard library will perform inequality comparison (i.e, '<')
  150. /// in the way that the second elements (RRClass) are compared only when
  151. /// the first elements are equivalent.
  152. /// In practice, when we compare two pairs of RRType and RRClass, RRClass
  153. /// would be the same (and, in particular, be class IN) in the majority of
  154. /// cases. So this comparison ordering should be more efficient in common
  155. /// cases.
  156. typedef pair<RRType, RRClass> RRTypeClass;
  157. typedef map<RRTypeClass, RdataFactoryPtr> RdataFactoryMap;
  158. typedef map<RRType, RdataFactoryPtr> GenericRdataFactoryMap;
  159. template <typename T>
  160. class OldRdataFactory : public AbstractRdataFactory {
  161. public:
  162. using AbstractRdataFactory::create;
  163. virtual RdataPtr create(const string& rdata_str) const
  164. {
  165. return (RdataPtr(new T(rdata_str)));
  166. }
  167. virtual RdataPtr create(InputBuffer& buffer, size_t rdata_len) const
  168. {
  169. return (RdataPtr(new T(buffer, rdata_len)));
  170. }
  171. virtual RdataPtr create(const Rdata& source) const
  172. {
  173. return (RdataPtr(new T(dynamic_cast<const T&>(source))));
  174. }
  175. };
  176. template <typename T>
  177. class RdataFactory : public OldRdataFactory<T> {
  178. public:
  179. using OldRdataFactory<T>::create;
  180. virtual RdataPtr create(MasterLexer& lexer, const Name* origin,
  181. MasterLoader::Options options,
  182. MasterLoaderCallbacks& callbacks) const {
  183. return (RdataPtr(new T(lexer, origin, options, callbacks)));
  184. }
  185. };
  186. ///
  187. /// \brief The \c RRParamRegistryImpl class is the actual implementation of
  188. /// \c RRParamRegistry.
  189. ///
  190. /// The implementation is hidden from applications. We can refer to specific
  191. /// members of this class only within the implementation source file.
  192. ///
  193. struct RRParamRegistryImpl {
  194. /// Mappings from RR type codes to textual representations.
  195. StrRRTypeMap str2typemap;
  196. /// Mappings from textual representations of RR types to integer codes.
  197. CodeRRTypeMap code2typemap;
  198. /// Mappings from RR class codes to textual representations.
  199. StrRRClassMap str2classmap;
  200. /// Mappings from textual representations of RR classes to integer codes.
  201. CodeRRClassMap code2classmap;
  202. RdataFactoryMap rdata_factories;
  203. GenericRdataFactoryMap genericrdata_factories;
  204. };
  205. RRParamRegistry::RRParamRegistry() {
  206. impl_ = new RRParamRegistryImpl;
  207. // set up parameters for well-known RRs
  208. try {
  209. // BEGIN_WELL_KNOWN_PARAMS
  210. // END_WELL_KNOWN_PARAMS
  211. } catch (...) {
  212. delete impl_;
  213. throw;
  214. }
  215. }
  216. RRParamRegistry::~RRParamRegistry() {
  217. delete impl_;
  218. }
  219. RRParamRegistry&
  220. RRParamRegistry::getRegistry() {
  221. static RRParamRegistry registry;
  222. return (registry);
  223. }
  224. void
  225. RRParamRegistry::add(const std::string& typecode_string, uint16_t typecode,
  226. RdataFactoryPtr rdata_factory)
  227. {
  228. bool type_added = false;
  229. try {
  230. type_added = addType(typecode_string, typecode);
  231. impl_->genericrdata_factories.insert(pair<RRType, RdataFactoryPtr>(
  232. RRType(typecode),
  233. rdata_factory));
  234. } catch (...) {
  235. if (type_added) {
  236. removeType(typecode);
  237. }
  238. throw;
  239. }
  240. }
  241. void
  242. RRParamRegistry::add(const std::string& typecode_string, uint16_t typecode,
  243. const std::string& classcode_string, uint16_t classcode,
  244. RdataFactoryPtr rdata_factory)
  245. {
  246. // Rollback logic on failure is complicated. If adding the new type or
  247. // class fails, we should revert to the original state, cleaning up
  248. // intermediate state. But we need to make sure that we don't remove
  249. // existing data. addType()/addClass() will simply ignore an attempt to
  250. // add the same data, so the cleanup should be performed only when we add
  251. // something new but we fail in other part of the process.
  252. bool type_added = false;
  253. bool class_added = false;
  254. try {
  255. type_added = addType(typecode_string, typecode);
  256. class_added = addClass(classcode_string, classcode);
  257. impl_->rdata_factories.insert(pair<RRTypeClass, RdataFactoryPtr>(
  258. RRTypeClass(RRType(typecode),
  259. RRClass(classcode)),
  260. rdata_factory));
  261. } catch (...) {
  262. if (type_added) {
  263. removeType(typecode);
  264. }
  265. if (class_added) {
  266. removeClass(classcode);
  267. }
  268. throw;
  269. }
  270. }
  271. bool
  272. RRParamRegistry::removeRdataFactory(const RRType& rrtype,
  273. const RRClass& rrclass)
  274. {
  275. RdataFactoryMap::iterator found =
  276. impl_->rdata_factories.find(RRTypeClass(rrtype, rrclass));
  277. if (found != impl_->rdata_factories.end()) {
  278. impl_->rdata_factories.erase(found);
  279. return (true);
  280. }
  281. return (false);
  282. }
  283. bool
  284. RRParamRegistry::removeRdataFactory(const RRType& rrtype) {
  285. GenericRdataFactoryMap::iterator found =
  286. impl_->genericrdata_factories.find(rrtype);
  287. if (found != impl_->genericrdata_factories.end()) {
  288. impl_->genericrdata_factories.erase(found);
  289. return (true);
  290. }
  291. return (false);
  292. }
  293. namespace {
  294. ///
  295. /// These are helper functions to implement case-insensitive string comparison.
  296. /// This could be simplified using strncasecmp(), but unfortunately it's not
  297. /// included in <cstring>. To be as much as portable within the C++ standard
  298. /// we take the "in house" approach here.
  299. ///
  300. bool CICharEqual(char c1, char c2) {
  301. return (tolower(static_cast<unsigned char>(c1)) ==
  302. tolower(static_cast<unsigned char>(c2)));
  303. }
  304. bool
  305. caseStringEqual(const string& s1, const string& s2, size_t n) {
  306. assert(s1.size() >= n && s2.size() >= n);
  307. return (mismatch(s1.begin(), s1.begin() + n, s2.begin(), CICharEqual).first
  308. == s1.begin() + n);
  309. }
  310. /// Code logic for RRTypes and RRClasses is mostly common except (C++) type and
  311. /// member names. So we define type-independent templates to describe the
  312. /// common logic and let concrete classes use it to avoid code duplicates.
  313. /// The following summarize template parameters used in the set of template
  314. /// functions:
  315. /// PT: parameter type, either RRTypeParam or RRClassParam
  316. /// MC: type of mapping class from code: either CodeRRTypeMap or CodeRRClassMap
  317. /// MS: type of mapping class from string: either StrRRTypeMap or StrRRClassMap
  318. /// ET: exception type for error handling: either InvalidRRType or
  319. /// InvalidRRClass
  320. template <typename PT, typename MC, typename MS, typename ET>
  321. inline bool
  322. addParam(const string& code_string, uint16_t code, MC& codemap, MS& stringmap)
  323. {
  324. // Duplicate type check
  325. typename MC::const_iterator found = codemap.find(code);
  326. if (found != codemap.end()) {
  327. if (found->second->code_string_ != code_string) {
  328. isc_throw(ET, "Duplicate RR parameter registration");
  329. }
  330. return (false);
  331. }
  332. typedef boost::shared_ptr<PT> ParamPtr;
  333. typedef pair<string, ParamPtr> StrParamPair;
  334. typedef pair<uint16_t, ParamPtr> CodeParamPair;
  335. ParamPtr param = ParamPtr(new PT(code_string, code));
  336. try {
  337. stringmap.insert(StrParamPair(code_string, param));
  338. codemap.insert(CodeParamPair(code, param));
  339. } catch (...) {
  340. // Rollback to the previous state: not all of the erase operations will
  341. // find the entry, but we don't care.
  342. stringmap.erase(code_string);
  343. codemap.erase(code);
  344. throw;
  345. }
  346. return (true);
  347. }
  348. template <typename MC, typename MS>
  349. inline bool
  350. removeParam(uint16_t code, MC& codemap, MS& stringmap) {
  351. typename MC::iterator found = codemap.find(code);
  352. if (found != codemap.end()) {
  353. size_t erased = stringmap.erase(found->second->code_string_);
  354. // We must have a corresponding entry of the str2 map exists
  355. assert(erased == 1);
  356. codemap.erase(found);
  357. return (true);
  358. }
  359. return (false);
  360. }
  361. template <typename PT, typename MS, typename ET>
  362. inline uint16_t
  363. textToCode(const string& code_str, MS& stringmap) {
  364. typename MS::const_iterator found;
  365. found = stringmap.find(code_str);
  366. if (found != stringmap.end()) {
  367. return (found->second->code_);
  368. }
  369. size_t l = code_str.size();
  370. if (l > PT::UNKNOWN_PREFIXLEN() &&
  371. l <= PT::UNKNOWN_MAXLEN() &&
  372. caseStringEqual(code_str, PT::UNKNOWN_PREFIX(),
  373. PT::UNKNOWN_PREFIXLEN())) {
  374. unsigned int code;
  375. istringstream iss(code_str.substr(PT::UNKNOWN_PREFIXLEN(),
  376. l - PT::UNKNOWN_PREFIXLEN()));
  377. iss >> dec >> code;
  378. if (iss.rdstate() == ios::eofbit && code <= PT::MAX_CODE) {
  379. return (code);
  380. }
  381. }
  382. isc_throw(ET, "Unrecognized RR parameter string: " + code_str);
  383. }
  384. template <typename PT, typename MC>
  385. inline string
  386. codeToText(uint16_t code, MC& codemap) {
  387. typename MC::const_iterator found;
  388. found = codemap.find(code);
  389. if (found != codemap.end()) {
  390. return (found->second->code_string_);
  391. }
  392. ostringstream ss;
  393. ss << code;
  394. return (PT::UNKNOWN_PREFIX() + ss.str());
  395. }
  396. }
  397. bool
  398. RRParamRegistry::addType(const string& type_string, uint16_t code) {
  399. return (addParam<RRTypeParam, CodeRRTypeMap, StrRRTypeMap, RRTypeExists>
  400. (type_string, code, impl_->code2typemap, impl_->str2typemap));
  401. }
  402. bool
  403. RRParamRegistry::removeType(uint16_t code) {
  404. return (removeParam<CodeRRTypeMap, StrRRTypeMap>(code, impl_->code2typemap,
  405. impl_->str2typemap));
  406. }
  407. uint16_t
  408. RRParamRegistry::textToTypeCode(const string& type_string) const {
  409. return (textToCode<RRTypeParam, StrRRTypeMap,
  410. InvalidRRType>(type_string, impl_->str2typemap));
  411. }
  412. string
  413. RRParamRegistry::codeToTypeText(uint16_t code) const {
  414. return (codeToText<RRTypeParam, CodeRRTypeMap>(code, impl_->code2typemap));
  415. }
  416. bool
  417. RRParamRegistry::addClass(const string& class_string, uint16_t code) {
  418. return (addParam<RRClassParam, CodeRRClassMap, StrRRClassMap, RRClassExists>
  419. (class_string, code, impl_->code2classmap, impl_->str2classmap));
  420. }
  421. bool
  422. RRParamRegistry::removeClass(uint16_t code) {
  423. return (removeParam<CodeRRClassMap, StrRRClassMap>(code,
  424. impl_->code2classmap,
  425. impl_->str2classmap));
  426. }
  427. uint16_t
  428. RRParamRegistry::textToClassCode(const string& class_string) const {
  429. return (textToCode<RRClassParam, StrRRClassMap,
  430. InvalidRRClass>(class_string, impl_->str2classmap));
  431. }
  432. string
  433. RRParamRegistry::codeToClassText(uint16_t code) const {
  434. return (codeToText<RRClassParam, CodeRRClassMap>(code,
  435. impl_->code2classmap));
  436. }
  437. RdataPtr
  438. RRParamRegistry::createRdata(const RRType& rrtype, const RRClass& rrclass,
  439. const std::string& rdata_string)
  440. {
  441. // If the text indicates that it's rdata of an "unknown" type (beginning
  442. // with '\# n'), parse it that way. (TBD)
  443. RdataFactoryMap::const_iterator found;
  444. found = impl_->rdata_factories.find(RRTypeClass(rrtype, rrclass));
  445. if (found != impl_->rdata_factories.end()) {
  446. return (found->second->create(rdata_string));
  447. }
  448. GenericRdataFactoryMap::const_iterator genfound =
  449. impl_->genericrdata_factories.find(rrtype);
  450. if (genfound != impl_->genericrdata_factories.end()) {
  451. return (genfound->second->create(rdata_string));
  452. }
  453. return (RdataPtr(new generic::Generic(rdata_string)));
  454. }
  455. RdataPtr
  456. RRParamRegistry::createRdata(const RRType& rrtype, const RRClass& rrclass,
  457. InputBuffer& buffer, size_t rdata_len)
  458. {
  459. RdataFactoryMap::const_iterator found =
  460. impl_->rdata_factories.find(RRTypeClass(rrtype, rrclass));
  461. if (found != impl_->rdata_factories.end()) {
  462. return (found->second->create(buffer, rdata_len));
  463. }
  464. GenericRdataFactoryMap::const_iterator genfound =
  465. impl_->genericrdata_factories.find(rrtype);
  466. if (genfound != impl_->genericrdata_factories.end()) {
  467. return (genfound->second->create(buffer, rdata_len));
  468. }
  469. return (RdataPtr(new generic::Generic(buffer, rdata_len)));
  470. }
  471. RdataPtr
  472. RRParamRegistry::createRdata(const RRType& rrtype, const RRClass& rrclass,
  473. const Rdata& source)
  474. {
  475. RdataFactoryMap::const_iterator found =
  476. impl_->rdata_factories.find(RRTypeClass(rrtype, rrclass));
  477. if (found != impl_->rdata_factories.end()) {
  478. return (found->second->create(source));
  479. }
  480. GenericRdataFactoryMap::const_iterator genfound =
  481. impl_->genericrdata_factories.find(rrtype);
  482. if (genfound != impl_->genericrdata_factories.end()) {
  483. return (genfound->second->create(source));
  484. }
  485. return (RdataPtr(new rdata::generic::Generic(
  486. dynamic_cast<const generic::Generic&>(source))));
  487. }
  488. RdataPtr
  489. RRParamRegistry::createRdata(const RRType& rrtype, const RRClass& rrclass,
  490. MasterLexer& lexer, const Name* name,
  491. MasterLoader::Options options,
  492. MasterLoaderCallbacks& callbacks)
  493. {
  494. RdataFactoryMap::const_iterator found =
  495. impl_->rdata_factories.find(RRTypeClass(rrtype, rrclass));
  496. if (found != impl_->rdata_factories.end()) {
  497. return (found->second->create(lexer, name, options, callbacks));
  498. }
  499. GenericRdataFactoryMap::const_iterator genfound =
  500. impl_->genericrdata_factories.find(rrtype);
  501. if (genfound != impl_->genericrdata_factories.end()) {
  502. return (genfound->second->create(lexer, name, options, callbacks));
  503. }
  504. return (RdataPtr(new generic::Generic(lexer, name, options, callbacks)));
  505. }
  506. }
  507. }