rrparamregistry-placeholder.cc 17 KB

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