option_int_array.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. // Copyright (C) 2012-2013,2015 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 OPTION_INT_ARRAY_H
  15. #define OPTION_INT_ARRAY_H
  16. #include <dhcp/libdhcp++.h>
  17. #include <dhcp/option.h>
  18. #include <dhcp/option_data_types.h>
  19. #include <util/io_utilities.h>
  20. #include <sstream>
  21. #include <stdint.h>
  22. namespace isc {
  23. namespace dhcp {
  24. /// Forward declaration of OptionIntArray.
  25. template<typename T>
  26. class OptionIntArray;
  27. /// @defgroup option_int_array_defs Typedefs for OptionIntArray class.
  28. ///
  29. /// @brief Classes that represent options comprising array of integers.
  30. ///
  31. /// @{
  32. typedef OptionIntArray<uint8_t> OptionUint8Array;
  33. typedef boost::shared_ptr<OptionUint8Array> OptionUint8ArrayPtr;
  34. typedef OptionIntArray<uint16_t> OptionUint16Array;
  35. typedef boost::shared_ptr<OptionUint16Array> OptionUint16ArrayPtr;
  36. typedef OptionIntArray<uint32_t> OptionUint32Array;
  37. typedef boost::shared_ptr<OptionUint32Array> OptionUint32ArrayPtr;
  38. /// @}
  39. /// This template class represents DHCP (v4 or v6) option with an
  40. /// array of integer values. The type of the elements in the array
  41. /// can be any of the following:
  42. /// - uint8_t,
  43. /// - uint16_t,
  44. /// - uint32_t,
  45. /// - int8_t,
  46. /// - int16_t,
  47. /// - int32_t.
  48. ///
  49. /// @warning Since this option may convey variable number of integer
  50. /// values, sub-options are should not be added in this option as
  51. /// there is no way to distinguish them from other data. The API will
  52. /// allow addition of sub-options but they will be ignored during
  53. /// packing and unpacking option data.
  54. ///
  55. /// @param T data field type (see above).
  56. template<typename T>
  57. class OptionIntArray: public Option {
  58. public:
  59. /// @brief Constructor.
  60. ///
  61. /// Creates option with empty values vector.
  62. ///
  63. /// @param u universe (V4 or V6).
  64. /// @param type option type.
  65. ///
  66. /// @throw isc::dhcp::InvalidDataType if data field type provided
  67. /// as template parameter is not a supported integer type.
  68. OptionIntArray(const Option::Universe u, const uint16_t type)
  69. : Option(u, type),
  70. values_(0) {
  71. if (!OptionDataTypeTraits<T>::integer_type) {
  72. isc_throw(dhcp::InvalidDataType, "non-integer type");
  73. }
  74. }
  75. /// @brief Constructor.
  76. ///
  77. /// @param u universe (V4 or V6).
  78. /// @param type option type.
  79. /// @param buf buffer with option data (must not be empty).
  80. ///
  81. /// @throw isc::OutOfRange if provided buffer is empty or its length
  82. /// is not multiple of size of the data type in bytes.
  83. /// @throw isc::dhcp::InvalidDataType if data field type provided
  84. /// as template parameter is not a supported integer type.
  85. OptionIntArray(const Option::Universe u, const uint16_t type,
  86. const OptionBuffer& buf)
  87. : Option(u, type) {
  88. if (!OptionDataTypeTraits<T>::integer_type) {
  89. isc_throw(dhcp::InvalidDataType, "non-integer type");
  90. }
  91. unpack(buf.begin(), buf.end());
  92. }
  93. /// @brief Constructor.
  94. ///
  95. /// This constructor creates option from a buffer. This constructor
  96. /// may throw exception if \ref unpack function throws during buffer
  97. /// parsing.
  98. ///
  99. /// @param u universe (V4 or V6).
  100. /// @param type option type.
  101. /// @param begin iterator to first byte of option data.
  102. /// @param end iterator to end of option data (first byte after option end).
  103. ///
  104. /// @throw isc::OutOfRange if provided buffer is empty or its length
  105. /// is not multiple of size of the data type in bytes.
  106. /// @throw isc::dhcp::InvalidDataType if data field type provided
  107. /// as template parameter is not a supported integer type.
  108. OptionIntArray(const Option::Universe u, const uint16_t type,
  109. OptionBufferConstIter begin, OptionBufferConstIter end)
  110. : Option(u, type) {
  111. if (!OptionDataTypeTraits<T>::integer_type) {
  112. isc_throw(dhcp::InvalidDataType, "non-integer type");
  113. }
  114. unpack(begin, end);
  115. }
  116. /// @brief Adds a new value to the array.
  117. ///
  118. /// @param value a value being added.
  119. void addValue(const T value) {
  120. values_.push_back(value);
  121. }
  122. /// Writes option in wire-format to buf, returns pointer to first unused
  123. /// byte after stored option.
  124. ///
  125. /// @param [out] buf buffer (option will be stored here)
  126. ///
  127. /// @throw isc::dhcp::InvalidDataType if size of a data fields type is not
  128. /// equal to 1, 2 or 4 bytes. The data type is not checked in this function
  129. /// because it is checked in a constructor.
  130. void pack(isc::util::OutputBuffer& buf) {
  131. // Pack option header.
  132. packHeader(buf);
  133. // Pack option data.
  134. for (int i = 0; i < values_.size(); ++i) {
  135. // Depending on the data type length we use different utility functions
  136. // writeUint16 or writeUint32 which write the data in the network byte
  137. // order to the provided buffer. The same functions can be safely used
  138. // for either unsigned or signed integers so there is not need to create
  139. // special cases for intX_t types.
  140. switch (OptionDataTypeTraits<T>::len) {
  141. case 1:
  142. buf.writeUint8(values_[i]);
  143. break;
  144. case 2:
  145. buf.writeUint16(values_[i]);
  146. break;
  147. case 4:
  148. buf.writeUint32(values_[i]);
  149. break;
  150. default:
  151. isc_throw(dhcp::InvalidDataType, "non-integer type");
  152. }
  153. }
  154. // We don't pack sub-options here because we have array-type option.
  155. // We don't allow sub-options in array-type options as there is no
  156. // way to distinguish them from the data fields on option reception.
  157. }
  158. /// @brief Parses received buffer
  159. ///
  160. /// Parses received buffer and returns offset to the first unused byte after
  161. /// parsed option.
  162. ///
  163. /// @param begin iterator to first byte of option data
  164. /// @param end iterator to end of option data (first byte after option end)
  165. ///
  166. /// @throw isc::dhcp::InvalidDataType if size of a data fields type is not
  167. /// equal to 1, 2 or 4 bytes. The data type is not checked in this function
  168. /// because it is checked in a constructor.
  169. virtual void unpack(OptionBufferConstIter begin, OptionBufferConstIter end) {
  170. if (distance(begin, end) == 0) {
  171. isc_throw(OutOfRange, "option " << getType() << " empty");
  172. }
  173. if (distance(begin, end) % sizeof(T) != 0) {
  174. isc_throw(OutOfRange, "option " << getType() << " truncated");
  175. }
  176. // @todo consider what to do if buffer is longer than data type.
  177. values_.clear();
  178. while (begin != end) {
  179. // Depending on the data type length we use different utility functions
  180. // readUint16 or readUint32 which read the data laid in the network byte
  181. // order from the provided buffer. The same functions can be safely used
  182. // for either unsigned or signed integers so there is not need to create
  183. // special cases for intX_t types.
  184. int data_size_len = OptionDataTypeTraits<T>::len;
  185. switch (data_size_len) {
  186. case 1:
  187. values_.push_back(*begin);
  188. break;
  189. case 2:
  190. values_.push_back(isc::util::readUint16(&(*begin),
  191. std::distance(begin, end)));
  192. break;
  193. case 4:
  194. values_.push_back(isc::util::readUint32(&(*begin),
  195. std::distance(begin, end)));
  196. break;
  197. default:
  198. isc_throw(dhcp::InvalidDataType, "non-integer type");
  199. }
  200. // Use local variable to set a new value for this iterator.
  201. // When using OptionDataTypeTraits<T>::len directly some versions
  202. // of clang complain about unresolved reference to
  203. // OptionDataTypeTraits structure during linking.
  204. begin += data_size_len;
  205. }
  206. // We do not unpack sub-options here because we have array-type option.
  207. // Such option have variable number of data fields, thus there is no
  208. // way to assess where sub-options start.
  209. }
  210. /// @brief Return collection of option values.
  211. ///
  212. /// @return collection of values.
  213. const std::vector<T>& getValues() const { return (values_); }
  214. /// @brief Set option values.
  215. ///
  216. /// @param values collection of values to be set for option.
  217. void setValues(const std::vector<T>& values) { values_ = values; }
  218. /// @brief returns complete length of option
  219. ///
  220. /// Returns length of this option, including option header and suboptions
  221. ///
  222. /// @return length of this option
  223. virtual uint16_t len() {
  224. uint16_t length = (getUniverse() == Option::V4) ? OPTION4_HDR_LEN : OPTION6_HDR_LEN;
  225. length += values_.size() * sizeof(T);
  226. // length of all suboptions
  227. for (OptionCollection::iterator it = options_.begin();
  228. it != options_.end();
  229. ++it) {
  230. length += (*it).second->len();
  231. }
  232. return (length);
  233. }
  234. /// @brief Returns textual representation of the option.
  235. ///
  236. /// @param indent Number of space characters to be inserted before
  237. /// the text.
  238. ///
  239. /// @return textual representation of the option.
  240. virtual std::string toText(int indent = 0) {
  241. std::stringstream output;
  242. output << headerToText(indent) << ":";
  243. std::string data_type = OptionDataTypeUtil::getDataTypeName(OptionDataTypeTraits<T>::type);
  244. for (typename std::vector<T>::const_iterator value = values_.begin();
  245. value != values_.end(); ++value) {
  246. output << " " << *value << " (" << data_type << ")";
  247. }
  248. return (output.str());
  249. }
  250. private:
  251. std::vector<T> values_;
  252. };
  253. } // isc::dhcp namespace
  254. } // isc namespace
  255. #endif // OPTION_INT_ARRAY_H