option6_int_array.h 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. // Copyright (C) 2012 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 OPTION6_INT_ARRAY_H_
  15. #define OPTION6_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 <stdint.h>
  21. namespace isc {
  22. namespace dhcp {
  23. /// This template class represents DHCPv6 option with array of
  24. /// integer values. The type of the elements in the array can be
  25. /// any of the following:
  26. /// - uint8_t,
  27. /// - uint16_t,
  28. /// - uint32_t,
  29. /// - int8_t,
  30. /// - int16_t,
  31. /// - int32_t.
  32. ///
  33. /// @warning Since this option may convey variable number of integer
  34. /// values, sub-options are should not be added in this option as
  35. /// there is no way to distinguish them from other data. The API will
  36. /// allow addition of sub-options but they will be ignored during
  37. /// packing and unpacking option data.
  38. ///
  39. /// @param T data field type (see above).
  40. template<typename T>
  41. class Option6IntArray: public Option {
  42. public:
  43. /// @brief Constructor.
  44. ///
  45. /// Creates option with empty values vector.
  46. ///
  47. /// @param type option type.
  48. ///
  49. /// @throw isc::dhcp::InvalidDataType if data field type provided
  50. /// as template parameter is not a supported integer type.
  51. Option6IntArray(uint16_t type)
  52. : Option(Option::V6, type),
  53. values_(0) {
  54. if (!OptionDataTypes<T>::valid) {
  55. isc_throw(dhcp::InvalidDataType, "non-integer type");
  56. }
  57. }
  58. /// @brief Constructor.
  59. ///
  60. /// @param type option type.
  61. /// @param buf buffer with option data (must not be empty).
  62. ///
  63. /// @throw isc::OutOfRange if provided buffer is empty or its length
  64. /// is not multiple of size of the data type in bytes.
  65. /// @throw isc::dhcp::InvalidDataType if data field type provided
  66. /// as template parameter is not a supported integer type.
  67. Option6IntArray(uint16_t type, const OptionBuffer& buf)
  68. : Option(Option::V6, type) {
  69. if (!OptionDataTypes<T>::valid) {
  70. isc_throw(dhcp::InvalidDataType, "non-integer type");
  71. }
  72. unpack(buf.begin(), buf.end());
  73. }
  74. /// @brief Constructor.
  75. ///
  76. /// This constructor creates option from a buffer. This construtor
  77. /// may throw exception if \ref unpack function throws during buffer
  78. /// parsing.
  79. ///
  80. /// @param type option type.
  81. /// @param begin iterator to first byte of option data.
  82. /// @param end iterator to end of option data (first byte after option end).
  83. ///
  84. /// @throw isc::OutOfRange if provided buffer is empty or its length
  85. /// is not multiple of size of the data type in bytes.
  86. /// @throw isc::dhcp::InvalidDataType if data field type provided
  87. /// as template parameter is not a supported integer type.
  88. Option6IntArray(uint16_t type, OptionBufferConstIter begin,
  89. OptionBufferConstIter end)
  90. : Option(Option::V6, type) {
  91. if (!OptionDataTypes<T>::valid) {
  92. isc_throw(dhcp::InvalidDataType, "non-integer type");
  93. }
  94. unpack(begin, end);
  95. }
  96. /// Writes option in wire-format to buf, returns pointer to first unused
  97. /// byte after stored option.
  98. ///
  99. /// @param [out] buf buffer (option will be stored here)
  100. ///
  101. /// @throw isc::dhcp::InvalidDataType if size of a data fields type is not
  102. /// equal to 1, 2 or 4 bytes. The data type is not checked in this function
  103. /// because it is checked in a constructor.
  104. void pack(isc::util::OutputBuffer& buf) {
  105. buf.writeUint16(type_);
  106. buf.writeUint16(len() - OPTION6_HDR_LEN);
  107. for (int i = 0; i < values_.size(); ++i) {
  108. // Depending on the data type length we use different utility functions
  109. // writeUint16 or writeUint32 which write the data in the network byte
  110. // order to the provided buffer. The same functions can be safely used
  111. // for either unsiged or signed integers so there is not need to create
  112. // special cases for intX_t types.
  113. switch (OptionDataTypes<T>::len) {
  114. case 1:
  115. buf.writeUint8(values_[i]);
  116. break;
  117. case 2:
  118. buf.writeUint16(values_[i]);
  119. break;
  120. case 4:
  121. buf.writeUint32(values_[i]);
  122. break;
  123. default:
  124. isc_throw(dhcp::InvalidDataType, "non-integer type");
  125. }
  126. }
  127. // We don't pack sub-options here because we have array-type option.
  128. // We don't allow sub-options in array-type options as there is no
  129. // way to distinguish them from the data fields on option reception.
  130. }
  131. /// @brief Parses received buffer
  132. ///
  133. /// Parses received buffer and returns offset to the first unused byte after
  134. /// parsed option.
  135. ///
  136. /// @param begin iterator to first byte of option data
  137. /// @param end iterator to end of option data (first byte after option end)
  138. ///
  139. /// @throw isc::dhcp::InvalidDataType if size of a data fields type is not
  140. /// equal to 1, 2 or 4 bytes. The data type is not checked in this function
  141. /// because it is checked in a constructor.
  142. virtual void unpack(OptionBufferConstIter begin, OptionBufferConstIter end) {
  143. if (distance(begin, end) == 0) {
  144. isc_throw(OutOfRange, "option " << getType() << " empty");
  145. }
  146. if (distance(begin, end) % sizeof(T) != 0) {
  147. isc_throw(OutOfRange, "option " << getType() << " truncated");
  148. }
  149. // @todo consider what to do if buffer is longer than data type.
  150. values_.clear();
  151. while (begin != end) {
  152. // Depending on the data type length we use different utility functions
  153. // readUint16 or readUint32 which read the data laid in the network byte
  154. // order from the provided buffer. The same functions can be safely used
  155. // for either unsiged or signed integers so there is not need to create
  156. // special cases for intX_t types.
  157. int data_size_len = OptionDataTypes<T>::len;
  158. switch (data_size_len) {
  159. case 1:
  160. values_.push_back(*begin);
  161. break;
  162. case 2:
  163. values_.push_back(isc::util::readUint16(&(*begin)));
  164. break;
  165. case 4:
  166. values_.push_back(isc::util::readUint32(&(*begin)));
  167. break;
  168. default:
  169. isc_throw(dhcp::InvalidDataType, "non-integer type");
  170. }
  171. // Use local variable to set a new value for this iterator.
  172. // When using OptionDataTypes<T>::len directly some versions
  173. // of clang complain about unresolved reference to
  174. // OptionDataTypes structure during linking.
  175. begin += data_size_len;
  176. }
  177. // We do not unpack sub-options here because we have array-type option.
  178. // Such option have variable number of data fields, thus there is no
  179. // way to assess where sub-options start.
  180. }
  181. /// @brief Return collection of option values.
  182. ///
  183. /// @return collection of values.
  184. const std::vector<T>& getValues() const { return (values_); }
  185. /// @brief Set option values.
  186. ///
  187. /// @param values collection of values to be set for option.
  188. void setValues(const std::vector<T>& values) { values_ = values; }
  189. /// @brief returns complete length of option
  190. ///
  191. /// Returns length of this option, including option header and suboptions
  192. ///
  193. /// @return length of this option
  194. virtual uint16_t len() {
  195. uint16_t length = OPTION6_HDR_LEN + values_.size() * sizeof(T);
  196. // length of all suboptions
  197. for (Option::OptionCollection::iterator it = options_.begin();
  198. it != options_.end();
  199. ++it) {
  200. length += (*it).second->len();
  201. }
  202. return (length);
  203. }
  204. private:
  205. std::vector<T> values_;
  206. };
  207. } // isc::dhcp namespace
  208. } // isc namespace
  209. #endif /* OPTION6_INT_ARRAY_H_ */