opaque_data_tuple.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  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 the 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_type Indicates a length of the field which holds
  65. /// the size of the tuple.
  66. OpaqueDataTuple(LengthFieldType length_field_type);
  67. /// @brief Constructor
  68. ///
  69. /// Creates a tuple from on-wire data. It calls @c OpaqueDataTuple::unpack
  70. /// internally.
  71. ///
  72. /// @param length_field_type Indicates the length of the field holding the
  73. /// opaque data size.
  74. /// @param begin Iterator pointing to the beginning of the buffer holding
  75. /// wire data.
  76. /// @param end Iterator pointing to the end of the buffer holding wire data.
  77. /// @tparam InputIterator Type of the iterators passed to this function.
  78. /// @throw It may throw an exception if the @c unpack throws.
  79. template<typename InputIterator>
  80. OpaqueDataTuple(LengthFieldType length_field_type, InputIterator begin,
  81. InputIterator end)
  82. : length_field_type_(length_field_type) {
  83. unpack(begin, end);
  84. }
  85. /// @brief Appends data to the tuple.
  86. ///
  87. /// This function appends the data of the specified length to the tuple.
  88. /// If the specified buffer length is greater than the size of the buffer,
  89. /// the behavior of this function is undefined.
  90. ///
  91. /// @param data Iterator pointing to the beginning of the buffer being
  92. /// appended. The source buffer may be an STL object or an array of
  93. /// characters. In the latter case, the pointer to the beginning of this
  94. /// array should be passed.
  95. /// @param len Length of the source buffer.
  96. /// @tparam InputIterator Type of the iterator pointing to the beginning of
  97. /// the source buffer.
  98. template<typename InputIterator>
  99. void append(InputIterator data, const size_t len) {
  100. data_.insert(data_.end(), data, data + len);
  101. }
  102. /// @brief Appends string to the tuple.
  103. ///
  104. /// In most cases, the tuple will carry a string. This function appends the
  105. /// string to the tuple.
  106. ///
  107. /// @param text String to be appended in the tuple.
  108. void append(const std::string& text);
  109. /// @brief Assigns data to the tuple.
  110. ///
  111. /// This function replaces existing data in the tuple with the new data.
  112. /// If the speficified buffer length is greater than the size of the buffer,
  113. /// the behavior of this function is undefined.
  114. /// @param data Iterator pointing to the beginning of the buffer being
  115. /// assigned. The source buffer may be an STL object or an array of
  116. /// characters. In the latter case, the pointer to the beginning of this
  117. /// array should be passed.
  118. /// @param len Length of the source buffer.
  119. /// @tparam InputIterator Type of the iterator pointing to the beginning of
  120. /// the source buffer.
  121. template<typename InputIterator>
  122. void assign(InputIterator data, const size_t len) {
  123. data_.assign(data, data + len);
  124. }
  125. /// @brief Assigns string data to the tuple.
  126. ///
  127. /// In most cases, the tuple will carry a string. This function sets the
  128. /// string to the tuple.
  129. ///
  130. /// @param text String to be assigned to the tuple.
  131. void assign(const std::string& text);
  132. /// @brief Removes the contents of the tuple.
  133. void clear();
  134. /// @brief Checks if the data carried in the tuple match the string.
  135. ///
  136. /// @param other String to compare tuple data against.
  137. bool equals(const std::string& other) const;
  138. /// @brief Returns tuple length data field type.
  139. LengthFieldType getLengthFieldType() const {
  140. return (length_field_type_);
  141. }
  142. /// @brief Returns the length of the data in the tuple.
  143. size_t getLength() const {
  144. return (data_.size());
  145. }
  146. /// @brief Returns a total size of the tuple, including length field.
  147. size_t getTotalLength() const {
  148. return (getDataFieldSize() + getLength());
  149. }
  150. /// @brief Returns a reference to the buffer holding tuple data.
  151. ///
  152. /// @warning The returned reference is valid only within the lifetime
  153. /// of the object which returned it. The use of the returned reference
  154. /// after the object has been destroyed yelds undefined behavior.
  155. const Buffer& getData() const {
  156. return (data_);
  157. }
  158. /// @brief Return the tuple data in the textual format.
  159. std::string getText() const;
  160. /// @brief Renders the tuple to a buffer in the wire format.
  161. ///
  162. /// This function creates the following wire representation of the tuple:
  163. /// - 1 or 2 bytes holding a length of the data.
  164. /// - variable number of bytes holding data.
  165. /// and writes it to the specified buffer. The new are appended to the
  166. /// buffer, so as data existing in the buffer is preserved.
  167. ///
  168. /// The tuple is considered malformed if one of the follwing occurs:
  169. /// - the size of the data is 0 (tuple is empty),
  170. /// - the size of the data is greater than 255 and the size of the length
  171. /// field is 1 byte (see @c LengthFieldType).
  172. /// - the size of the data is greater than 65535 and the size of the length
  173. /// field is 2 bytes (see @c LengthFieldType).
  174. ///
  175. /// Function will throw an exception if trying to render malformed tuple.
  176. ///
  177. /// @param [out] buf Buffer to which the data is rendered.
  178. ///
  179. /// @throw OpaqueDataTupleError if failed to render the data to the
  180. /// buffer because the tuple is malformed.
  181. void pack(isc::util::OutputBuffer& buf) const;
  182. /// @brief Parses wire data and creates a tuple from it.
  183. ///
  184. /// This function parses on-wire data stored in the provided buffer and
  185. /// stores it in the tuple object. The wire data must include at least the
  186. /// data field of the length matching the specified @c LengthFieldType.
  187. /// The remaining buffer length (excluding the length field) must be equal
  188. /// or greater than the length carried in the length field. If any of these
  189. /// two conditions is not met, an exception is thrown.
  190. ///
  191. /// This function allows opaque data with the length of 0.
  192. ///
  193. /// @param begin Iterator pointing to the beginning of the buffer holding
  194. /// wire data.
  195. /// @param end Iterator pointing to the end of the buffer holding wire data.
  196. /// @tparam InputIterator Type of the iterators passed to this function.
  197. template<typename InputIterator>
  198. void unpack(InputIterator begin, InputIterator end) {
  199. Buffer buf(begin, end);
  200. // The buffer must at least hold the size of the data.
  201. if (std::distance(begin, end) < getDataFieldSize()) {
  202. isc_throw(OpaqueDataTupleError,
  203. "unable to parse the opaque data tuple, the buffer"
  204. " length is " << std::distance(begin, end)
  205. << ", expected at least " << getDataFieldSize());
  206. }
  207. // Read the data length from the length field, depending on the
  208. // size of the data field (1 or 2 bytes).
  209. size_t len = getDataFieldSize() == 1 ? *begin :
  210. isc::util::readUint16(&(*begin), std::distance(begin, end));
  211. // Now that we have the expected data size, let's check that the
  212. // reminder of the buffer is long enough.
  213. begin += getDataFieldSize();
  214. if (std::distance(begin, end) < len) {
  215. isc_throw(OpaqueDataTupleError,
  216. "unable to parse the opaque data tuple, the buffer"
  217. " length is " << std::distance(begin, end)
  218. << ", but the length of the tuple in the length field"
  219. " is " << len);
  220. }
  221. // The buffer length is long enough to read the desired amount of data.
  222. assign(begin, len);
  223. }
  224. /// @name Assignment and comparison operators.
  225. //{@
  226. /// @brief Assignment operator.
  227. ///
  228. /// This operator assigns the string data to the tuple.
  229. ///
  230. /// @param other string to be assigned to the tuple.
  231. /// @return Tuple object after assignment.
  232. OpaqueDataTuple& operator=(const std::string& other);
  233. /// @brief Equality operator.
  234. ///
  235. /// This operator compares the string given as an argument to the data
  236. /// carried in the tuple in the textual format.
  237. ///
  238. /// @param other String to compare the tuple against.
  239. /// @return true if data carried in the tuple is equal to the string.
  240. bool operator==(const std::string& other) const;
  241. /// @brief Inequality operator.
  242. ///
  243. /// This operator compares the string given as an argument to the data
  244. /// carried in the tuple for inequality.
  245. ///
  246. /// @param other String to compare the tuple against.
  247. /// @return true if the data carried in the tuple is unequal the given
  248. /// string.
  249. bool operator!=(const std::string& other);
  250. //@}
  251. /// @brief Returns the size of the tuple length field.
  252. ///
  253. /// The returned value depends on the @c LengthFieldType set for the tuple.
  254. int getDataFieldSize() const;
  255. private:
  256. /// @brief Buffer which holds the opaque tuple data.
  257. Buffer data_;
  258. /// @brief Holds a type of tuple size field (1 byte long or 2 bytes long).
  259. LengthFieldType length_field_type_;
  260. };
  261. /// @brief Pointer to the @c OpaqueDataTuple object.
  262. typedef boost::shared_ptr<OpaqueDataTuple> OpaqueDataTuplePtr;
  263. /// @brief Inserts the @c OpaqueDataTuple as a string into stream.
  264. ///
  265. /// This operator gets the tuple data in the textual format and inserts it
  266. /// into the output stream.
  267. ///
  268. /// @param os Stream object on which insertion is performed.
  269. /// @param tuple Object encapsulating a tuple which data in the textual format
  270. /// is inserted into the stream.
  271. /// @return Reference to the same stream but after insertion operation.
  272. std::ostream& operator<<(std::ostream& os, const OpaqueDataTuple& tuple);
  273. /// @brief Inserts data carried in the stream into the tuple.
  274. ///
  275. /// this operator inserts data carried in the input stream and inserts it to
  276. /// the @c OpaqueDataTuple object. The existing data is replaced with new data.
  277. ///
  278. /// @param is Input stream from which the data will be inserted.
  279. /// @param tuple @c OpaqueDataTuple object to which the data will be inserted.
  280. /// @return Input stream after insertion to the tuple is performed.
  281. std::istream& operator>>(std::istream& is, OpaqueDataTuple& tuple);
  282. } // namespace isc::dhcp
  283. } // namespace isc
  284. #endif