rrparamregistry-placeholder.cc 16 KB

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