rdatafields.cc 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  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 <stdint.h>
  15. #include <cassert>
  16. #include <vector>
  17. #include <exceptions/exceptions.h>
  18. #include <dns/buffer.h>
  19. #include <dns/messagerenderer.h>
  20. #include <dns/name.h>
  21. #include <dns/rdata.h>
  22. #include <dns/rdatafields.h>
  23. using namespace std;
  24. using namespace isc::dns;
  25. using namespace isc::dns::rdata;
  26. namespace isc {
  27. namespace dns {
  28. namespace rdata {
  29. /// This is a helper class for \c RdataFields.
  30. ///
  31. /// It manages a local storage for the data when \c RdataFields is constructed
  32. /// from an \c Rdata.
  33. /// The implementation is hidden here to hide non portable details such as
  34. /// std::vector.
  35. /// To minimize construction overhead in the other case, an instance of
  36. /// this class is instantiated only when necessary.
  37. struct RdataFields::RdataFieldsDetail {
  38. RdataFieldsDetail(const vector<FieldSpec>& fields,
  39. const void* data, size_t data_length) :
  40. allocated_fields_(fields),
  41. allocated_data_(static_cast<const uint8_t*>(data),
  42. static_cast<const uint8_t*>(data) + data_length)
  43. {}
  44. const vector<FieldSpec> allocated_fields_;
  45. const vector<uint8_t> allocated_data_;
  46. };
  47. namespace {
  48. // This class is used to divide the content of RDATA into \c RdataField
  49. // fields via message rendering logic.
  50. // The idea is to identify domain name fields in the writeName() method,
  51. // and determine whether they are compressible using the "compress"
  52. // parameter.
  53. // Other types of data are simply copied into the internal buffer, and
  54. // consecutive such fields are combined into a single \c RdataField field.
  55. //
  56. // Technically, this use of inheritance may be considered a violation of
  57. // Liskov Substitution Principle in that it doesn't actually compress domain
  58. // names, and some of the methods are not expected to be used.
  59. // In fact, skip() or trim() may not be well defined for the purpose of this
  60. // class.
  61. // Nevertheless we keep this idea at the moment. Since the usage is limited
  62. // (it's only used within this file, and only used with \c Rdata variants),
  63. // it's hopefully an acceptable practice.
  64. class RdataFieldComposer : public AbstractMessageRenderer {
  65. public:
  66. RdataFieldComposer(OutputBuffer& buffer) :
  67. buffer_(buffer), truncated_(false), length_limit_(65535),
  68. mode_(CASE_INSENSITIVE)
  69. {}
  70. virtual ~RdataFieldComposer() {}
  71. virtual const void* getData() const { return (buffer_.getData()); }
  72. virtual size_t getLength() const { return (buffer_.getLength()); }
  73. virtual bool isTruncated() const { return (truncated_); }
  74. virtual size_t getLengthLimit() const { return (length_limit_); }
  75. virtual CompressMode getCompressMode() const { return (mode_); }
  76. virtual void setTruncated() { truncated_ = true; }
  77. virtual void setLengthLimit(size_t len) { length_limit_ = len; }
  78. virtual void setCompressMode(CompressMode mode) { mode_ = mode; }
  79. virtual void writeUint8(uint8_t data);
  80. virtual void writeUint16(uint16_t data);
  81. virtual void writeUint32(uint32_t data);
  82. virtual void writeData(const void *data, size_t len);
  83. virtual void writeName(const Name& name, bool compress);
  84. virtual void clear() {
  85. isc_throw(Unexpected, "unexpected clear() for RdataFieldComposer");
  86. }
  87. virtual void skip(size_t) {
  88. isc_throw(Unexpected, "unexpected skip() for RdataFieldComposer");
  89. }
  90. virtual void trim(size_t) {
  91. isc_throw(Unexpected, "unexpected trim() for RdataFieldComposer");
  92. }
  93. virtual void writeUint16At(uint16_t, size_t) {
  94. isc_throw(Unexpected,
  95. "unexpected writeUint16At() for RdataFieldComposer");
  96. }
  97. OutputBuffer buffer_;
  98. bool truncated_;
  99. size_t length_limit_;
  100. CompressMode mode_;
  101. vector<RdataFields::FieldSpec> fields_;
  102. };
  103. void
  104. RdataFieldComposer::writeUint8(uint8_t data) {
  105. buffer_.writeUint8(data);
  106. if (fields_.empty() || fields_.back().type != RdataFields::DATA) {
  107. fields_.push_back(RdataFields::FieldSpec(RdataFields::DATA, 0));
  108. }
  109. fields_.back().len += sizeof(data);
  110. }
  111. void
  112. RdataFieldComposer::writeUint16(uint16_t data) {
  113. buffer_.writeUint16(data);
  114. if (fields_.empty() || fields_.back().type != RdataFields::DATA) {
  115. fields_.push_back(RdataFields::FieldSpec(RdataFields::DATA, 0));
  116. }
  117. fields_.back().len += sizeof(data);
  118. }
  119. void
  120. RdataFieldComposer::writeUint32(uint32_t data) {
  121. buffer_.writeUint32(data);
  122. if (fields_.empty() || fields_.back().type != RdataFields::DATA) {
  123. fields_.push_back(RdataFields::FieldSpec(RdataFields::DATA, 0));
  124. }
  125. fields_.back().len += sizeof(data);
  126. }
  127. void
  128. RdataFieldComposer::writeData(const void *data, size_t len) {
  129. buffer_.writeData(data, len);
  130. if (fields_.empty() || fields_.back().type != RdataFields::DATA) {
  131. fields_.push_back(RdataFields::FieldSpec(RdataFields::DATA, 0));
  132. }
  133. fields_.back().len += len;
  134. }
  135. void
  136. RdataFieldComposer::writeName(const Name& name, bool compress) {
  137. const RdataFields::Type field_type =
  138. compress ? RdataFields::COMPRESSIBLE_NAME :
  139. RdataFields::INCOMPRESSIBLE_NAME;
  140. name.toWire(buffer_);
  141. fields_.push_back(RdataFields::FieldSpec(field_type, name.getLength()));
  142. }
  143. }
  144. RdataFields::RdataFields(const Rdata& rdata) {
  145. OutputBuffer buffer(0);
  146. RdataFieldComposer field_composer(buffer);
  147. rdata.toWire(field_composer);
  148. nfields_ = field_composer.fields_.size();
  149. data_length_ = field_composer.getLength();
  150. if (nfields_ > 0) {
  151. assert(data_length_ > 0);
  152. detail_ = new RdataFieldsDetail(field_composer.fields_,
  153. field_composer.getData(),
  154. field_composer.getLength());
  155. data_ = &detail_->allocated_data_[0];
  156. fields_ = &detail_->allocated_fields_[0];
  157. } else {
  158. assert(data_length_ == 0);
  159. detail_ = NULL;
  160. data_ = NULL;
  161. fields_ = NULL;
  162. }
  163. }
  164. RdataFields::RdataFields(const FieldSpec* fields, const unsigned int nfields,
  165. const uint8_t* data, const size_t data_length) :
  166. fields_(fields), nfields_(nfields), data_(data), data_length_(data_length),
  167. detail_(NULL)
  168. {
  169. if ((fields_ == NULL && nfields_ > 0) ||
  170. (fields_ != NULL && nfields_ == 0)) {
  171. isc_throw(InvalidParameter,
  172. "Inconsistent parameters for RdataFields: nfields ("
  173. << nfields_ << ") and fields conflict each other");
  174. }
  175. if ((data_ == NULL && data_length_ > 0) ||
  176. (data_ != NULL && data_length_ == 0)) {
  177. isc_throw(InvalidParameter,
  178. "Inconsistent parameters for RdataFields: data length ("
  179. << data_length_ << ") and data conflict each other");
  180. }
  181. size_t total_length = 0;
  182. for (int i = 0; i < nfields_; ++i) {
  183. total_length += fields_[i].len;
  184. }
  185. if (total_length != data_length_) {
  186. isc_throw(InvalidParameter,
  187. "Inconsistent parameters for RdataFields; "
  188. "fields len: " << total_length <<
  189. " data len: " << data_length_);
  190. }
  191. }
  192. RdataFields::~RdataFields() {
  193. delete detail_;
  194. }
  195. RdataFields::FieldSpec
  196. RdataFields::getFieldSpec(const unsigned int field_id) const {
  197. if (field_id >= nfields_) {
  198. isc_throw(OutOfRange, "Rdata field ID is out of range: " << field_id);
  199. }
  200. return (fields_[field_id]);
  201. }
  202. void
  203. RdataFields::toWire(AbstractMessageRenderer& renderer) const {
  204. size_t offset = 0;
  205. for (int i = 0; i < nfields_; ++i) {
  206. if (fields_[i].type == DATA) {
  207. renderer.writeData(data_ + offset, fields_[i].len);
  208. } else {
  209. // XXX: this is inefficient. Even if it's quite likely the
  210. // data is a valid wire representation of a name we parse
  211. // it to construct the Name object in the generic mode.
  212. // This should be improved in a future version.
  213. InputBuffer buffer(data_ + offset, fields_[i].len);
  214. renderer.writeName(Name(buffer),
  215. fields_[i].type == COMPRESSIBLE_NAME ?
  216. true : false);
  217. }
  218. offset += fields_[i].len;
  219. }
  220. }
  221. void
  222. RdataFields::toWire(OutputBuffer& buffer) const {
  223. buffer.writeData(data_, data_length_);
  224. }
  225. } // end of namespace rdata
  226. } // end of namespace dns
  227. } // end of namespace isc