option_int.h 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. // Copyright (C) 2012-2013 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_H
  15. #define OPTION_INT_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 DHCP option with single value.
  24. /// This value is of integer type and can be any of the following:
  25. /// - uint8_t,
  26. /// - uint16_t,
  27. /// - uint32_t,
  28. /// - int8_t,
  29. /// - int16_t,
  30. /// - int32_t.
  31. ///
  32. /// @param T data field type (see above).
  33. template<typename T>
  34. class OptionInt: public Option {
  35. public:
  36. /// @brief Constructor.
  37. ///
  38. /// @param u universe (V4 or V6)
  39. /// @param type option type.
  40. /// @param value option value.
  41. ///
  42. /// @throw isc::dhcp::InvalidDataType if data field type provided
  43. /// as template parameter is not a supported integer type.
  44. /// @todo Extend constructor to set encapsulated option space name.
  45. OptionInt(Option::Universe u, uint16_t type, T value)
  46. : Option(u, type), value_(value) {
  47. if (!OptionDataTypeTraits<T>::integer_type) {
  48. isc_throw(dhcp::InvalidDataType, "non-integer type");
  49. }
  50. setEncapsulatedSpace(u == Option::V4 ? "dhcp4" : "dhcp6");
  51. }
  52. /// @brief Constructor.
  53. ///
  54. /// This constructor creates option from a buffer. This constructor
  55. /// may throw exception if \ref unpack function throws during buffer
  56. /// parsing.
  57. ///
  58. /// @param u universe (V4 or V6)
  59. /// @param type option type.
  60. /// @param begin iterator to first byte of option data.
  61. /// @param end iterator to end of option data (first byte after option end).
  62. ///
  63. /// @throw isc::OutOfRange if provided buffer is shorter than data size.
  64. /// @throw isc::dhcp::InvalidDataType if data field type provided
  65. /// as template parameter is not a supported integer type.
  66. /// @todo Extend constructor to set encapsulated option space name.
  67. OptionInt(Option::Universe u, uint16_t type, OptionBufferConstIter begin,
  68. OptionBufferConstIter end)
  69. : Option(u, type) {
  70. if (!OptionDataTypeTraits<T>::integer_type) {
  71. isc_throw(dhcp::InvalidDataType, "non-integer type");
  72. }
  73. setEncapsulatedSpace(u == Option::V4 ? "dhcp4" : "dhcp6");
  74. unpack(begin, end);
  75. }
  76. /// Writes option in wire-format to buf, returns pointer to first unused
  77. /// byte after stored option.
  78. ///
  79. /// @param [out] buf buffer (option will be stored here)
  80. ///
  81. /// @throw isc::dhcp::InvalidDataType if size of a data field type is not
  82. /// equal to 1, 2 or 4 bytes. The data type is not checked in this function
  83. /// because it is checked in a constructor.
  84. void pack(isc::util::OutputBuffer& buf) {
  85. // Pack option header.
  86. packHeader(buf);
  87. // Depending on the data type length we use different utility functions
  88. // writeUint16 or writeUint32 which write the data in the network byte
  89. // order to the provided buffer. The same functions can be safely used
  90. // for either unsigned or signed integers so there is not need to create
  91. // special cases for intX_t types.
  92. switch (OptionDataTypeTraits<T>::len) {
  93. case 1:
  94. buf.writeUint8(value_);
  95. break;
  96. case 2:
  97. buf.writeUint16(value_);
  98. break;
  99. case 4:
  100. buf.writeUint32(value_);
  101. break;
  102. default:
  103. isc_throw(dhcp::InvalidDataType, "non-integer type");
  104. }
  105. packOptions(buf);
  106. }
  107. /// @brief Parses received buffer
  108. ///
  109. /// Parses received buffer and returns offset to the first unused byte after
  110. /// parsed option.
  111. ///
  112. /// @param begin iterator to first byte of option data
  113. /// @param end iterator to end of option data (first byte after option end)
  114. ///
  115. /// @throw isc::OutOfRange if provided buffer is shorter than data size.
  116. /// @throw isc::dhcp::InvalidDataType if size of a data field type is not
  117. /// equal to 1, 2 or 4 bytes. The data type is not checked in this function
  118. /// because it is checked in a constructor.
  119. virtual void unpack(OptionBufferConstIter begin, OptionBufferConstIter end) {
  120. if (distance(begin, end) < sizeof(T)) {
  121. isc_throw(OutOfRange, "Option " << getType() << " truncated");
  122. }
  123. // @todo consider what to do if buffer is longer than data type.
  124. // Depending on the data type length we use different utility functions
  125. // readUint16 or readUint32 which read the data laid in the network byte
  126. // order from the provided buffer. The same functions can be safely used
  127. // for either unsigned or signed integers so there is not need to create
  128. // special cases for intX_t types.
  129. int data_size_len = OptionDataTypeTraits<T>::len;
  130. switch (data_size_len) {
  131. case 1:
  132. value_ = *begin;
  133. break;
  134. case 2:
  135. value_ = isc::util::readUint16(&(*begin),
  136. std::distance(begin, end));
  137. break;
  138. case 4:
  139. value_ = isc::util::readUint32(&(*begin),
  140. std::distance(begin, end));
  141. break;
  142. default:
  143. isc_throw(dhcp::InvalidDataType, "non-integer type");
  144. }
  145. // Use local variable to set a new value for this iterator.
  146. // When using OptionDataTypeTraits<T>::len directly some versions
  147. // of clang complain about unresolved reference to
  148. // OptionDataTypeTraits structure during linking.
  149. begin += data_size_len;
  150. unpackOptions(OptionBuffer(begin, end));
  151. }
  152. /// @brief Set option value.
  153. ///
  154. /// @param value new option value.
  155. void setValue(T value) { value_ = value; }
  156. /// @brief Return option value.
  157. ///
  158. /// @return option value.
  159. T getValue() const { return value_; }
  160. /// @brief returns complete length of option
  161. ///
  162. /// Returns length of this option, including option header and suboptions
  163. ///
  164. /// @return length of this option
  165. virtual uint16_t len() {
  166. // Calculate the length of the header.
  167. uint16_t length = (getUniverse() == Option::V4) ? OPTION4_HDR_LEN : OPTION6_HDR_LEN;
  168. // The data length is equal to size of T.
  169. length += sizeof(T);;
  170. // length of all suboptions
  171. for (OptionCollection::iterator it = options_.begin();
  172. it != options_.end();
  173. ++it) {
  174. length += (*it).second->len();
  175. }
  176. return (length);
  177. }
  178. private:
  179. T value_; ///< Value conveyed by the option.
  180. };
  181. } // isc::dhcp namespace
  182. } // isc namespace
  183. #endif // OPTION_INT_H