rrparamregistry-placeholder.cc 16 KB

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