txt_like.h 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. // Copyright (C) 2011 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. #ifndef __TXT_LIKE_H
  15. #define __TXT_LIKE_H 1
  16. #include <stdint.h>
  17. #include <string>
  18. #include <vector>
  19. using namespace std;
  20. using namespace isc::util;
  21. /// \brief \c rdata::TXTLikeImpl class represents the TXT-like RDATA for TXT
  22. /// and SPF types.
  23. ///
  24. /// This class implements the basic interfaces inherited by the TXT and SPF
  25. /// classes from the abstract \c rdata::Rdata class, and provides trivial
  26. /// accessors to TXT-like RDATA.
  27. template<class Type, uint16_t typeCode>class TXTLikeImpl {
  28. public:
  29. /// \brief Constructor from wire-format data.
  30. ///
  31. /// \param buffer A buffer storing the wire format data.
  32. /// \param rdata_len The length of the RDATA in bytes, normally expected
  33. /// to be the value of the RDLENGTH field of the corresponding RR.
  34. ///
  35. /// <b>Exceptions</b>
  36. ///
  37. /// \c InvalidRdataLength is thrown if rdata_len exceeds the maximum.
  38. /// \c DNSMessageFORMERR is thrown if the RR is misformed.
  39. TXTLikeImpl(InputBuffer& buffer, size_t rdata_len) {
  40. if (rdata_len > MAX_RDLENGTH) {
  41. isc_throw(InvalidRdataLength, "RDLENGTH too large: " << rdata_len);
  42. }
  43. if (rdata_len == 0) { // note that this couldn't happen in the loop.
  44. isc_throw(DNSMessageFORMERR, "Error in parsing " <<
  45. RRType(typeCode) << " RDATA: 0-length character string");
  46. }
  47. do {
  48. const uint8_t len = buffer.readUint8();
  49. if (rdata_len < len + 1) {
  50. isc_throw(DNSMessageFORMERR, "Error in parsing " <<
  51. RRType(typeCode) <<
  52. " RDATA: character string length is too large: " <<
  53. static_cast<int>(len));
  54. }
  55. vector<uint8_t> data(len + 1);
  56. data[0] = len;
  57. buffer.readData(&data[0] + 1, len);
  58. string_list_.push_back(data);
  59. rdata_len -= (len + 1);
  60. } while (rdata_len > 0);
  61. }
  62. /// \brief Constructor from string.
  63. ///
  64. /// <b>Exceptions</b>
  65. ///
  66. /// \c CharStringTooLong is thrown if the parameter string length exceeds
  67. /// maximum.
  68. /// \c InvalidRdataText is thrown if the method cannot process the
  69. /// parameter data.
  70. explicit TXTLikeImpl(const std::string& txtstr) {
  71. // TBD: this is a simple, incomplete implementation that only supports
  72. // a single character-string.
  73. size_t length = txtstr.size();
  74. size_t pos_begin = 0;
  75. if (length > 1 && txtstr[0] == '"' && txtstr[length - 1] == '"') {
  76. pos_begin = 1;
  77. length -= 2;
  78. }
  79. if (length > MAX_CHARSTRING_LEN) {
  80. isc_throw(CharStringTooLong, RRType(typeCode) <<
  81. " RDATA construction from text:"
  82. " string length is too long: " << length);
  83. }
  84. // TBD: right now, we don't support escaped characters
  85. if (txtstr.find('\\') != string::npos) {
  86. isc_throw(InvalidRdataText, RRType(typeCode) <<
  87. " RDATA from text:"
  88. " escaped character is currently not supported: " <<
  89. txtstr);
  90. }
  91. vector<uint8_t> data;
  92. data.reserve(length + 1);
  93. data.push_back(length);
  94. data.insert(data.end(), txtstr.begin() + pos_begin,
  95. txtstr.begin() + pos_begin + length);
  96. string_list_.push_back(data);
  97. }
  98. /// \brief The copy constructor.
  99. ///
  100. /// Trivial for now, we could've used the default one.
  101. TXTLikeImpl(const TXTLikeImpl& other) :
  102. string_list_(other.string_list_)
  103. {}
  104. /// \brief Render the TXT-like data in the wire format to an OutputBuffer
  105. /// object.
  106. ///
  107. /// \param buffer An output buffer to store the wire data.
  108. void
  109. toWire(OutputBuffer& buffer) const {
  110. for (vector<vector<uint8_t> >::const_iterator it =
  111. string_list_.begin();
  112. it != string_list_.end();
  113. ++it)
  114. {
  115. buffer.writeData(&(*it)[0], (*it).size());
  116. }
  117. }
  118. /// \brief Render the TXT-like data in the wire format to an
  119. /// AbstractMessageRenderer object.
  120. ///
  121. /// \param buffer An output AbstractMessageRenderer to send the wire data
  122. /// to.
  123. void
  124. toWire(AbstractMessageRenderer& renderer) const {
  125. for (vector<vector<uint8_t> >::const_iterator it =
  126. string_list_.begin();
  127. it != string_list_.end();
  128. ++it)
  129. {
  130. renderer.writeData(&(*it)[0], (*it).size());
  131. }
  132. }
  133. /// \brief Convert the TXT-like data to a string.
  134. ///
  135. /// \return A \c string object that represents the TXT-like data.
  136. string
  137. toText() const {
  138. string s;
  139. // XXX: this implementation is not entirely correct. for example, it
  140. // should escape double-quotes if they appear in the character string.
  141. for (vector<vector<uint8_t> >::const_iterator it =
  142. string_list_.begin();
  143. it != string_list_.end();
  144. ++it)
  145. {
  146. if (!s.empty()) {
  147. s.push_back(' ');
  148. }
  149. s.push_back('"');
  150. s.insert(s.end(), (*it).begin() + 1, (*it).end());
  151. s.push_back('"');
  152. }
  153. return (s);
  154. }
  155. /// \brief Compare two instances of \c TSIG RDATA.
  156. ///
  157. /// It is up to the caller to make sure that \c other is an object of the
  158. /// same \c TXTLikeImpl class.
  159. ///
  160. /// \param other the right-hand operand to compare against.
  161. /// \return < 0 if \c this would be sorted before \c other.
  162. /// \return 0 if \c this is identical to \c other in terms of sorting
  163. /// order.
  164. /// \return > 0 if \c this would be sorted after \c other.
  165. int
  166. compare(const TXTLikeImpl& other) const {
  167. // This implementation is not efficient. Revisit this (TBD).
  168. OutputBuffer this_buffer(0);
  169. toWire(this_buffer);
  170. size_t this_len = this_buffer.getLength();
  171. OutputBuffer other_buffer(0);
  172. other.toWire(other_buffer);
  173. const size_t other_len = other_buffer.getLength();
  174. const size_t cmplen = min(this_len, other_len);
  175. const int cmp = memcmp(this_buffer.getData(), other_buffer.getData(),
  176. cmplen);
  177. if (cmp != 0) {
  178. return (cmp);
  179. } else {
  180. return ((this_len == other_len) ? 0 :
  181. (this_len < other_len) ? -1 : 1);
  182. }
  183. }
  184. private:
  185. /// Note: this is a prototype version; we may reconsider
  186. /// this representation later.
  187. std::vector<std::vector<uint8_t> > string_list_;
  188. };
  189. // END_RDATA_NAMESPACE
  190. // END_ISC_NAMESPACE
  191. #endif // __TXT_LIKE_H
  192. // Local Variables:
  193. // mode: c++
  194. // End: