opaque_data_tuple.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. // Copyright (C) 2014 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 OPAQUE_DATA_TUPLE_H
  15. #define OPAQUE_DATA_TUPLE_H
  16. #include <util/buffer.h>
  17. #include <util/io_utilities.h>
  18. #include <iostream>
  19. #include <iterator>
  20. #include <string>
  21. #include <vector>
  22. namespace isc {
  23. namespace dhcp {
  24. /// @brief Exception to be thrown when there operation on @c OpaqueDataTuple
  25. /// object results in an error.
  26. class OpaqueDataTupleError : public Exception {
  27. public:
  28. OpaqueDataTupleError(const char* file, size_t line, const char* what) :
  29. isc::Exception(file, line, what) { };
  30. };
  31. /// @brief Represents a single instance of the opaque data preceded by length.
  32. ///
  33. /// Some of the DHCP options, such as Vendor Class option (16) in DHCPv6 or
  34. /// V-I Vendor Class option (124) in DHCPv4 may carry multiple pairs of
  35. /// opaque-data preceded by its length. Such pairs are called tuples. This class
  36. /// represents a single instance of the tuple in the DHCPv4 or DHCPv6 option.
  37. ///
  38. /// Although, the primary purpose of this class is to represent data tuples in
  39. /// Vendor Class options, there may be other options defined in the future that
  40. /// may have similar structure and this class can be used to represent the data
  41. /// tuples in these new options too.
  42. ///
  43. /// This class exposes a set of convenience methods to assign and retrieve the
  44. /// opaque data from the tuple. It also implements a method to render the tuple
  45. /// data into a wire format, as well as a method to create an instance of the
  46. /// tuple from the wire format.
  47. class OpaqueDataTuple {
  48. public:
  49. /// @brief Size of the length field in the tuple.
  50. ///
  51. /// In the wire format, the tuple consists of the two fields: one holding
  52. /// a length of the opaque data size, second holding opaque data. The first
  53. /// field's size may be equal to 1 or 2 bytes. Usually, the tuples carried
  54. /// in the DHCPv6 options have 2 byte long length fields, the tuples carried
  55. /// in DHCPv4 options have 1 byte long length fields.
  56. enum LengthFieldType {
  57. LENGTH_1_BYTE,
  58. LENGTH_2_BYTES
  59. };
  60. /// @brief Defines a type of the data buffer used to hold the opaque data.
  61. typedef std::vector<uint8_t> Buffer;
  62. /// @brief Default constructor.
  63. ///
  64. /// @param length_field_size Length of the field which holds the size of
  65. /// the tuple.
  66. OpaqueDataTuple(LengthFieldType length_field_type = LENGTH_2_BYTES);
  67. /// @brief Constructor
  68. ///
  69. /// Creates a tuple from on-wire data. It calls @c OpaqueDataTuple::unpack
  70. /// internally.
  71. ///
  72. /// @param begin Iterator pointing to the begining of the buffer holding
  73. /// wire data.
  74. /// @param end Iterator pointing to the end of the buffer holding wire data.
  75. /// @tparam InputIterator Type of the iterators passed to this function.
  76. /// @throw It may throw an exception if the @unpack throws.
  77. template<typename InputIterator>
  78. OpaqueDataTuple(LengthFieldType length_field_type, InputIterator begin,
  79. InputIterator end)
  80. : length_field_type_(length_field_type) {
  81. unpack(begin, end);
  82. }
  83. /// @brief Appends data to the tuple.
  84. ///
  85. /// This function appends the data of the specified length to the tuple.
  86. /// If the speficified buffer length is greater than the size of the buffer,
  87. /// the behavior of this function is undefined.
  88. ///
  89. /// @param data Iterator pointing to the beginning of the buffer being
  90. /// appended. The source buffer may be an STL object or an array of
  91. /// characters. In the latter case, the pointer to the beginning of this
  92. /// array should be passed.
  93. /// @param len Length of the source buffer.
  94. /// @tparam InputIterator Type of the iterator pointing to the beginning of
  95. /// the source buffer.
  96. template<typename InputIterator>
  97. void append(InputIterator data, const size_t len) {
  98. data_.insert(data_.end(), data, data + len);
  99. }
  100. /// @brief Appends string to the tuple.
  101. ///
  102. /// In most cases, the tuple will carry a string. This function appends the
  103. /// string to the tuple.
  104. ///
  105. /// @param text String to be appended in the tuple.
  106. void append(const std::string& text);
  107. /// @brief Assigns data to the tuple.
  108. ///
  109. /// This function replaces existing data in the tuple with the new data.
  110. /// If the speficified buffer length is greater than the size of the buffer,
  111. /// the behavior of this function is undefined.
  112. /// @param data Iterator pointing to the beginning of the buffer being
  113. /// assigned. The source buffer may be an STL object or an array of
  114. /// characters. In the latter case, the pointer to the beginning of this
  115. /// array should be passed.
  116. /// @param len Length of the source buffer.
  117. /// @tparam InputIterator Type of the iterator pointing to the beginning of
  118. /// the source buffer.
  119. template<typename InputIterator>
  120. void assign(InputIterator data, const size_t len) {
  121. data_.assign(data, data + len);
  122. }
  123. /// @brief Assigns string data to the tuple.
  124. ///
  125. /// In most cases, the tuple will carry a string. This function sets the
  126. /// string to the tuple.
  127. ///
  128. /// @param text String to be assigned to the tuple.
  129. void assign(const std::string& text);
  130. /// @brief Removes the contents of the tuple.
  131. void clear();
  132. /// @brief Checks if the data carried in the tuple match the string.
  133. ///
  134. /// @param other String to compare tuple data against.
  135. bool equals(const std::string& other) const;
  136. /// @brief Returns tuple length data field type.
  137. LengthFieldType getLengthFieldType() const {
  138. return (length_field_type_);
  139. }
  140. /// @brief Returns the length of the data in the tuple.
  141. size_t getLength() const {
  142. return (data_.size());
  143. }
  144. /// @brief Returns a total size of the tuple, including length field.
  145. size_t getTotalLength() const {
  146. return (getDataFieldSize() + getLength());
  147. }
  148. /// @brief Returns a reference to the buffer holding tuple data.
  149. ///
  150. /// @warning The returned reference is valid only within the lifetime
  151. /// of the object which returned it. The use of the returned reference
  152. /// after the object has been destroyed yelds undefined behavior.
  153. const Buffer& getData() const {
  154. return (data_);
  155. }
  156. /// @brief Return the tuple data in the textual format.
  157. std::string getText() const;
  158. /// @brief Renders the tuple to a buffer in the wire format.
  159. ///
  160. /// This function creates the following wire representation of the tuple:
  161. /// - 1 or 2 bytes holding a length of the data.
  162. /// - variable number of bytes holding data.
  163. /// and writes it to the specified buffer. The new are appended to the
  164. /// buffer, so as data existing in the buffer is preserved.
  165. ///
  166. /// The tuple is considered malformed if one of the follwing occurs:
  167. /// - the size of the data is 0 (tuple is empty),
  168. /// - the size of the data is greater than 255 and the size of the length
  169. /// field is 1 byte (see @c LengthFieldType).
  170. /// - the size of the data is greater than 65535 and the size of the length
  171. /// field is 2 bytes (see @c LengthFieldType).
  172. ///
  173. /// Function will throw an exception if trying to render malformed tuple.
  174. ///
  175. /// @param [out] buf Buffer to which the data is rendered.
  176. ///
  177. /// @throw OpaqueDataTupleError if failed to render the data to the
  178. /// buffer because the tuple is malformed.
  179. void pack(isc::util::OutputBuffer& buf) const;
  180. /// @brief Parses wire data and creates a tuple from it.
  181. ///
  182. /// This function parses on-wire data stored in the provided buffer and
  183. /// stores it in the tuple object. The wire data must include at least the
  184. /// data field of the length matching the specified @c LengthFieldType.
  185. /// The remaining buffer length (excluding the length field) must be equal
  186. /// or greater than the length carried in the length field. If any of these
  187. /// two conditions is not met, an exception is thrown.
  188. ///
  189. /// This function allows opaque data with the length of 0.
  190. ///
  191. /// @param begin Iterator pointing to the begining of the buffer holding
  192. /// wire data.
  193. /// @param end Iterator pointing to the end of the buffer holding wire data.
  194. /// @tparam InputIterator Type of the iterators passed to this function.
  195. template<typename InputIterator>
  196. void unpack(InputIterator begin, InputIterator end) {
  197. Buffer buf(begin, end);
  198. // The buffer must at least hold the size of the data.
  199. if (std::distance(begin, end) < getDataFieldSize()) {
  200. isc_throw(OpaqueDataTupleError,
  201. "unable to parse the opaque data tuple, the buffer"
  202. " length is " << std::distance(begin, end)
  203. << ", expected at least " << getDataFieldSize());
  204. }
  205. // Read the data length from the length field, depending on the
  206. // size of the data field (1 or 2 bytes).
  207. size_t len = getDataFieldSize() == 1 ? *begin :
  208. isc::util::readUint16(&(*begin), std::distance(begin, end));
  209. // Now that we have the expected data size, let's check that the
  210. // reminder of the buffer is long enough.
  211. begin += getDataFieldSize();
  212. if (std::distance(begin, end) < len) {
  213. isc_throw(OpaqueDataTupleError,
  214. "unable to parse the opaque data tuple, the buffer"
  215. " length is " << std::distance(begin, end)
  216. << ", but the length of the tuple in the length field"
  217. " is " << len);
  218. }
  219. // The buffer length is long enough to read the desired amount of data.
  220. assign(begin, len);
  221. }
  222. /// @name Assignment and comparison operators.
  223. //{@
  224. /// @brief Assignment operator.
  225. ///
  226. /// This operator assigns the string data to the tuple.
  227. ///
  228. /// @param other string to be assigned to the tuple.
  229. /// @return Tuple object after assignment.
  230. OpaqueDataTuple& operator=(const std::string& other);
  231. /// @brief Equality operator.
  232. ///
  233. /// This operator compares the string given as an argument to the data
  234. /// carried in the tuple in the textual format.
  235. ///
  236. /// @param other String to compare the tuple against.
  237. /// @return true if data carried in the tuple is equal to the string.
  238. bool operator==(const std::string& other) const;
  239. /// @brief Inequality operator.
  240. ///
  241. /// This operator compares the string given as an argument to the data
  242. /// carried in the tuple for inequality.
  243. ///
  244. /// @param other String to compare the tuple against.
  245. /// @return true if the data carried in the tuple is unequal the given
  246. /// string.
  247. bool operator!=(const std::string& other);
  248. //@}
  249. /// @brief Returns the size of the tuple length field.
  250. ///
  251. /// The returned value depends on the @c LengthFieldType set for the tuple.
  252. int getDataFieldSize() const;
  253. private:
  254. /// @brief Buffer which holds the opaque tuple data.
  255. Buffer data_;
  256. /// @brief Holds a type of tuple size field (1 byte long or 2 bytes long).
  257. LengthFieldType length_field_type_;
  258. };
  259. /// @brief Pointer to the @c OpaqueDataTuple object.
  260. typedef boost::shared_ptr<OpaqueDataTuple> OpaqueDataTuplePtr;
  261. /// @brief Inserts the @c OpaqueDataTuple as a string into stream.
  262. ///
  263. /// This operator gets the tuple data in the textual format and inserts it
  264. /// into the output stream.
  265. ///
  266. /// @param os Stream object on which insertion is performed.
  267. /// @param tuple Object encapsulating a tuple which data in the textual format
  268. /// is inserted into the stream.
  269. /// @return Reference to the same stream but after insertion operation.
  270. std::ostream& operator<<(std::ostream& os, const OpaqueDataTuple& tuple);
  271. /// @brief Inserts data carried in the stream into the tuple.
  272. ///
  273. /// this operator inserts data carried in the input stream and inserts it to
  274. /// the @c OpaqueDataTuple object. The existing data is replaced with new data.
  275. ///
  276. /// @param is Input stream from which the data will be inserted.
  277. /// @param tuple @c OpaqueDataTuple object to which the data will be inserted.
  278. /// @return Input stream after insertion to the tuple is performed.
  279. std::istream& operator>>(std::istream& is, OpaqueDataTuple& tuple);
  280. } // namespace isc::dhcp
  281. } // namespace isc
  282. #endif