option_int.h 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. // Copyright (C) 2012-2015 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_H
  7. #define OPTION_INT_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 <stdint.h>
  13. #include <sstream>
  14. namespace isc {
  15. namespace dhcp {
  16. template<typename T>
  17. class OptionInt;
  18. /// @defgroup option_int_defs Typedefs for OptionInt class.
  19. ///
  20. /// @brief Classes that represent options comprising an integer.
  21. ///
  22. /// @{
  23. typedef OptionInt<uint8_t> OptionUint8;
  24. typedef boost::shared_ptr<OptionUint8> OptionUint8Ptr;
  25. typedef OptionInt<uint16_t> OptionUint16;
  26. typedef boost::shared_ptr<OptionUint16> OptionUint16Ptr;
  27. typedef OptionInt<uint32_t> OptionUint32;
  28. typedef boost::shared_ptr<OptionUint32> OptionUint32Ptr;
  29. /// @}
  30. /// This template class represents DHCP option with single value.
  31. /// This value is of integer type and can be any of the following:
  32. /// - uint8_t,
  33. /// - uint16_t,
  34. /// - uint32_t,
  35. /// - int8_t,
  36. /// - int16_t,
  37. /// - int32_t.
  38. ///
  39. /// @param T data field type (see above).
  40. template<typename T>
  41. class OptionInt: public Option {
  42. public:
  43. /// @brief Constructor.
  44. ///
  45. /// @param u universe (V4 or V6)
  46. /// @param type option type.
  47. /// @param value option value.
  48. ///
  49. /// @throw isc::dhcp::InvalidDataType if data field type provided
  50. /// as template parameter is not a supported integer type.
  51. /// @todo Extend constructor to set encapsulated option space name.
  52. OptionInt(Option::Universe u, uint16_t type, T value)
  53. : Option(u, type), value_(value) {
  54. if (!OptionDataTypeTraits<T>::integer_type) {
  55. isc_throw(dhcp::InvalidDataType, "non-integer type");
  56. }
  57. setEncapsulatedSpace(u == Option::V4 ? "dhcp4" : "dhcp6");
  58. }
  59. /// @brief Constructor.
  60. ///
  61. /// This constructor creates option from a buffer. This constructor
  62. /// may throw exception if \ref unpack function throws during buffer
  63. /// parsing.
  64. ///
  65. /// @param u universe (V4 or V6)
  66. /// @param type option type.
  67. /// @param begin iterator to first byte of option data.
  68. /// @param end iterator to end of option data (first byte after option end).
  69. ///
  70. /// @throw isc::OutOfRange if provided buffer is shorter than data size.
  71. /// @throw isc::dhcp::InvalidDataType if data field type provided
  72. /// as template parameter is not a supported integer type.
  73. /// @todo Extend constructor to set encapsulated option space name.
  74. OptionInt(Option::Universe u, uint16_t type, OptionBufferConstIter begin,
  75. OptionBufferConstIter end)
  76. : Option(u, type) {
  77. if (!OptionDataTypeTraits<T>::integer_type) {
  78. isc_throw(dhcp::InvalidDataType, "non-integer type");
  79. }
  80. setEncapsulatedSpace(u == Option::V4 ? "dhcp4" : "dhcp6");
  81. unpack(begin, end);
  82. }
  83. /// Writes option in wire-format to buf, returns pointer to first unused
  84. /// byte after stored option.
  85. ///
  86. /// @param [out] buf buffer (option will be stored here)
  87. ///
  88. /// @throw isc::dhcp::InvalidDataType if size of a data field type is not
  89. /// equal to 1, 2 or 4 bytes. The data type is not checked in this function
  90. /// because it is checked in a constructor.
  91. void pack(isc::util::OutputBuffer& buf) const {
  92. // Pack option header.
  93. packHeader(buf);
  94. // Depending on the data type length we use different utility functions
  95. // writeUint16 or writeUint32 which write the data in the network byte
  96. // order to the provided buffer. The same functions can be safely used
  97. // for either unsigned or signed integers so there is not need to create
  98. // special cases for intX_t types.
  99. switch (OptionDataTypeTraits<T>::len) {
  100. case 1:
  101. buf.writeUint8(value_);
  102. break;
  103. case 2:
  104. buf.writeUint16(value_);
  105. break;
  106. case 4:
  107. buf.writeUint32(value_);
  108. break;
  109. default:
  110. isc_throw(dhcp::InvalidDataType, "non-integer type");
  111. }
  112. packOptions(buf);
  113. }
  114. /// @brief Parses received buffer
  115. ///
  116. /// Parses received buffer and returns offset to the first unused byte after
  117. /// parsed option.
  118. ///
  119. /// @param begin iterator to first byte of option data
  120. /// @param end iterator to end of option data (first byte after option end)
  121. ///
  122. /// @throw isc::OutOfRange if provided buffer is shorter than data size.
  123. /// @throw isc::dhcp::InvalidDataType if size of a data field type is not
  124. /// equal to 1, 2 or 4 bytes. The data type is not checked in this function
  125. /// because it is checked in a constructor.
  126. virtual void unpack(OptionBufferConstIter begin, OptionBufferConstIter end) {
  127. if (distance(begin, end) < sizeof(T)) {
  128. isc_throw(OutOfRange, "Option " << getType() << " truncated");
  129. }
  130. // @todo consider what to do if buffer is longer than data type.
  131. // Depending on the data type length we use different utility functions
  132. // readUint16 or readUint32 which read the data laid in the network byte
  133. // order from the provided buffer. The same functions can be safely used
  134. // for either unsigned or signed integers so there is not need to create
  135. // special cases for intX_t types.
  136. int data_size_len = OptionDataTypeTraits<T>::len;
  137. switch (data_size_len) {
  138. case 1:
  139. value_ = *begin;
  140. break;
  141. case 2:
  142. value_ = isc::util::readUint16(&(*begin),
  143. std::distance(begin, end));
  144. break;
  145. case 4:
  146. value_ = isc::util::readUint32(&(*begin),
  147. std::distance(begin, end));
  148. break;
  149. default:
  150. isc_throw(dhcp::InvalidDataType, "non-integer type");
  151. }
  152. // Use local variable to set a new value for this iterator.
  153. // When using OptionDataTypeTraits<T>::len directly some versions
  154. // of clang complain about unresolved reference to
  155. // OptionDataTypeTraits structure during linking.
  156. begin += data_size_len;
  157. unpackOptions(OptionBuffer(begin, end));
  158. }
  159. /// @brief Set option value.
  160. ///
  161. /// @param value new option value.
  162. void setValue(T value) { value_ = value; }
  163. /// @brief Return option value.
  164. ///
  165. /// @return option value.
  166. T getValue() const { return value_; }
  167. /// @brief returns complete length of option
  168. ///
  169. /// Returns length of this option, including option header and suboptions
  170. ///
  171. /// @return length of this option
  172. virtual uint16_t len() const {
  173. // Calculate the length of the header.
  174. uint16_t length = (getUniverse() == Option::V4) ? OPTION4_HDR_LEN : OPTION6_HDR_LEN;
  175. // The data length is equal to size of T.
  176. length += sizeof(T);;
  177. // length of all suboptions
  178. for (OptionCollection::const_iterator it = options_.begin();
  179. it != options_.end();
  180. ++it) {
  181. length += (*it).second->len();
  182. }
  183. return (length);
  184. }
  185. /// @brief Returns option carrying an integer value in the textual
  186. /// format.
  187. ///
  188. /// The returned value also includes the suboptions if present.
  189. ///
  190. /// @param indent Number of spaces to be inserted before the text.
  191. virtual std::string toText(int indent = 0) const {
  192. std::stringstream output;
  193. output << headerToText(indent) << ": ";
  194. // For 1 byte long data types we need to cast to the integer
  195. // because they are usually implemented as "char" types, in
  196. // which case the character rather than number would be printed.
  197. if (OptionDataTypeTraits<T>::len == 1) {
  198. output << static_cast<int>(getValue());
  199. } else {
  200. output << getValue();
  201. }
  202. // Append data type name.
  203. output << " ("
  204. << OptionDataTypeUtil::getDataTypeName(OptionDataTypeTraits<T>::type)
  205. << ")";
  206. // Append suboptions.
  207. output << suboptionsToText(indent + 2);
  208. return (output.str());
  209. }
  210. private:
  211. T value_; ///< Value conveyed by the option.
  212. };
  213. } // isc::dhcp namespace
  214. } // isc namespace
  215. #endif // OPTION_INT_H