option_int_array.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. // Copyright (C) 2012-2016 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this
  5. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. #ifndef OPTION_INT_ARRAY_H
  7. #define OPTION_INT_ARRAY_H
  8. #include <dhcp/libdhcp++.h>
  9. #include <dhcp/option.h>
  10. #include <dhcp/option_data_types.h>
  11. #include <util/io_utilities.h>
  12. #include <boost/shared_ptr.hpp>
  13. #include <sstream>
  14. #include <stdint.h>
  15. namespace isc {
  16. namespace dhcp {
  17. /// Forward declaration of OptionIntArray.
  18. template<typename T>
  19. class OptionIntArray;
  20. /// @defgroup option_int_array_defs Typedefs for OptionIntArray class.
  21. ///
  22. /// @brief Classes that represent options comprising array of integers.
  23. ///
  24. /// @{
  25. typedef OptionIntArray<uint8_t> OptionUint8Array;
  26. typedef boost::shared_ptr<OptionUint8Array> OptionUint8ArrayPtr;
  27. typedef OptionIntArray<uint16_t> OptionUint16Array;
  28. typedef boost::shared_ptr<OptionUint16Array> OptionUint16ArrayPtr;
  29. typedef OptionIntArray<uint32_t> OptionUint32Array;
  30. typedef boost::shared_ptr<OptionUint32Array> OptionUint32ArrayPtr;
  31. /// @}
  32. /// This template class represents DHCP (v4 or v6) option with an
  33. /// array of integer values. The type of the elements in the array
  34. /// can be any of the following:
  35. /// - uint8_t,
  36. /// - uint16_t,
  37. /// - uint32_t,
  38. /// - int8_t,
  39. /// - int16_t,
  40. /// - int32_t.
  41. ///
  42. /// @warning Since this option may convey variable number of integer
  43. /// values, sub-options are should not be added in this option as
  44. /// there is no way to distinguish them from other data. The API will
  45. /// allow addition of sub-options but they will be ignored during
  46. /// packing and unpacking option data.
  47. ///
  48. /// @param T data field type (see above).
  49. template<typename T>
  50. class OptionIntArray: public Option {
  51. private:
  52. /// @brief Pointer to the option type for the specified T.
  53. typedef boost::shared_ptr<OptionIntArray<T> > OptionIntArrayTypePtr;
  54. public:
  55. /// @brief Constructor.
  56. ///
  57. /// Creates option with empty values vector.
  58. ///
  59. /// @param u universe (V4 or V6).
  60. /// @param type option type.
  61. ///
  62. /// @throw isc::dhcp::InvalidDataType if data field type provided
  63. /// as template parameter is not a supported integer type.
  64. OptionIntArray(const Option::Universe u, const uint16_t type)
  65. : Option(u, type),
  66. values_(0) {
  67. if (!OptionDataTypeTraits<T>::integer_type) {
  68. isc_throw(dhcp::InvalidDataType, "non-integer type");
  69. }
  70. }
  71. /// @brief Constructor.
  72. ///
  73. /// @param u universe (V4 or V6).
  74. /// @param type option type.
  75. /// @param buf buffer with option data (must not be empty).
  76. ///
  77. /// @throw isc::OutOfRange if provided buffer is empty or its length
  78. /// is not multiple of size of the data type in bytes.
  79. /// @throw isc::dhcp::InvalidDataType if data field type provided
  80. /// as template parameter is not a supported integer type.
  81. OptionIntArray(const Option::Universe u, const uint16_t type,
  82. const OptionBuffer& buf)
  83. : Option(u, type) {
  84. if (!OptionDataTypeTraits<T>::integer_type) {
  85. isc_throw(dhcp::InvalidDataType, "non-integer type");
  86. }
  87. unpack(buf.begin(), buf.end());
  88. }
  89. /// @brief Constructor.
  90. ///
  91. /// This constructor creates option from a buffer. This constructor
  92. /// may throw exception if \ref unpack function throws during buffer
  93. /// parsing.
  94. ///
  95. /// @param u universe (V4 or V6).
  96. /// @param type option type.
  97. /// @param begin iterator to first byte of option data.
  98. /// @param end iterator to end of option data (first byte after option end).
  99. ///
  100. /// @throw isc::OutOfRange if provided buffer is empty or its length
  101. /// is not multiple of size of the data type in bytes.
  102. /// @throw isc::dhcp::InvalidDataType if data field type provided
  103. /// as template parameter is not a supported integer type.
  104. OptionIntArray(const Option::Universe u, const uint16_t type,
  105. OptionBufferConstIter begin, OptionBufferConstIter end)
  106. : Option(u, type) {
  107. if (!OptionDataTypeTraits<T>::integer_type) {
  108. isc_throw(dhcp::InvalidDataType, "non-integer type");
  109. }
  110. unpack(begin, end);
  111. }
  112. /// @brief Copies this option and returns a pointer to the copy.
  113. virtual OptionPtr clone() const {
  114. return (cloneInternal<OptionIntArray<T> >());
  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) const {
  131. // Pack option header.
  132. packHeader(buf);
  133. // Pack option data.
  134. for (size_t 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() const {
  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::const_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) const {
  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 << " ";
  247. // For 1 byte long data types we need to cast to the integer
  248. // because they are usually implemented as "char" types, in
  249. // which case the character rather than number would be printed.
  250. if (OptionDataTypeTraits<T>::len == 1) {
  251. output << static_cast<int>(*value);
  252. } else {
  253. output << *value;
  254. }
  255. // Append data type.
  256. output << "(" << data_type << ")";
  257. }
  258. return (output.str());
  259. }
  260. private:
  261. std::vector<T> values_;
  262. };
  263. } // isc::dhcp namespace
  264. } // isc namespace
  265. #endif // OPTION_INT_ARRAY_H