option_custom.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  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_CUSTOM_H
  15. #define OPTION_CUSTOM_H
  16. #include <dhcp/option.h>
  17. #include <dhcp/option_definition.h>
  18. #include <util/io_utilities.h>
  19. namespace isc {
  20. namespace dhcp {
  21. /// @brief Option with defined data fields represented as buffers that can
  22. /// be accessed using data field index.
  23. ///
  24. /// This class represents an option which has defined structure: data fields
  25. /// of specific types and order. Those fields can be accessed using indexes,
  26. /// where index 0 represents first data field within an option. The last
  27. /// field can be accessed using index equal to 'number of fields' - 1.
  28. /// Internally, the option data is stored as a collection of OptionBuffer
  29. /// objects, each representing data for a particular data field. This data
  30. /// can be converted to the actual data type using methods implemented
  31. /// within this class. This class is used to represent those options that
  32. /// can't be represented by any other specialized class (this excludes the
  33. /// Option class which is generic and can be used to represent any option).
  34. class OptionCustom : public Option {
  35. public:
  36. /// @brief Constructor, used for options to be sent.
  37. ///
  38. /// This constructor creates an instance of an option with default
  39. /// data set for all data fields. The option buffers are allocated
  40. /// according to data size being stored in particular data fields.
  41. /// For variable size data empty buffers are created.
  42. ///
  43. /// @param def option definition.
  44. /// @param u specifies universe (V4 or V6)
  45. OptionCustom(const OptionDefinition& def, Universe u);
  46. /// @brief Constructor, used for options to be sent.
  47. ///
  48. /// This constructor creates an instance of an option from the whole
  49. /// supplied buffer. This constructor is mainly used to create an
  50. /// instances of options to be stored in outgoing DHCP packets.
  51. /// The buffer used to create the instance of an option can be
  52. /// created from the option data specified in server's configuration.
  53. ///
  54. /// @param def option definition.
  55. /// @param u specifies universe (V4 or V6).
  56. /// @param data content of the option.
  57. ///
  58. /// @throw OutOfRange if option buffer is truncated.
  59. ///
  60. /// @todo list all exceptions thrown by ctor.
  61. OptionCustom(const OptionDefinition& def, Universe u, const OptionBuffer& data);
  62. /// @brief Constructor, used for received options.
  63. ///
  64. /// This constructor creates an instance an option from the portion
  65. /// of the buffer specified by iterators. This is mainly useful when
  66. /// parsing received packets. Such packets are represented by a single
  67. /// buffer holding option data and all sub options. Methods that are
  68. /// parsing a packet, supply relevant portions of the packet buffer
  69. /// to this constructor to create option instances out of it.
  70. ///
  71. /// @param def option definition.
  72. /// @param u specifies universe (V4 or V6).
  73. /// @param first iterator to the first element that should be copied.
  74. /// @param last iterator to the next element after the last one
  75. /// to be copied.
  76. ///
  77. /// @throw OutOfRange if option buffer is truncated.
  78. ///
  79. /// @todo list all exceptions thrown by ctor.
  80. OptionCustom(const OptionDefinition& def, Universe u,
  81. OptionBufferConstIter first, OptionBufferConstIter last);
  82. /// @brief Create new buffer and set its value as an IP address.
  83. ///
  84. /// @param address IPv4 or IPv6 address to be written to
  85. /// a buffer being created.
  86. void addArrayDataField(const asiolink::IOAddress& address);
  87. /// @brief Create new buffer and store boolean value in it.
  88. ///
  89. /// @param value value to be stored in the created buffer.
  90. void addArrayDataField(const bool value);
  91. /// @brief Create new buffer and store integer value in it.
  92. ///
  93. /// @param value value to be stored in the created buffer.
  94. /// @tparam T integer type of the value being stored.
  95. template<typename T>
  96. void addArrayDataField(const T value) {
  97. checkArrayType();
  98. OptionDataType data_type = definition_.getType();
  99. if (OptionDataTypeTraits<T>::type != data_type) {
  100. isc_throw(isc::dhcp::InvalidDataType,
  101. "specified data type " << data_type << " does not"
  102. " match the data type in an option definition");
  103. }
  104. OptionBuffer buf;
  105. OptionDataTypeUtil::writeInt<T>(value, buf);
  106. buffers_.push_back(buf);
  107. }
  108. /// @brief Return a number of the data fields.
  109. ///
  110. /// @return number of data fields held by the option.
  111. uint32_t getDataFieldsNum() const { return (buffers_.size()); }
  112. /// @brief Read a buffer as IP address.
  113. ///
  114. /// @param index buffer index.
  115. ///
  116. /// @return IP address read from a buffer.
  117. /// @throw isc::OutOfRange if index is out of range.
  118. asiolink::IOAddress readAddress(const uint32_t index = 0) const;
  119. /// @brief Write an IP address into a buffer.
  120. ///
  121. /// @param address IP address being written.
  122. /// @param index buffer index.
  123. ///
  124. /// @throw isc::OutOfRange if index is out of range.
  125. /// @throw isc::dhcp::BadDataTypeCast if IP address is invalid.
  126. void writeAddress(const asiolink::IOAddress& address,
  127. const uint32_t index = 0);
  128. /// @brief Read a buffer as binary data.
  129. ///
  130. /// @param index buffer index.
  131. ///
  132. /// @throw isc::OutOfRange if index is out of range.
  133. /// @return read buffer holding binary data.
  134. const OptionBuffer& readBinary(const uint32_t index = 0) const;
  135. /// @brief Write binary data into a buffer.
  136. ///
  137. /// @param buf buffer holding binary data to be written.
  138. /// @param index buffer index.
  139. void writeBinary(const OptionBuffer& buf, const uint32_t index = 0);
  140. /// @brief Read a buffer as boolean value.
  141. ///
  142. /// @param index buffer index.
  143. ///
  144. /// @throw isc::OutOfRange if index is out of range.
  145. /// @return read boolean value.
  146. bool readBoolean(const uint32_t index = 0) const;
  147. /// @brief Write a boolean value into a buffer.
  148. ///
  149. /// @param value boolean value to be written.
  150. /// @param index buffer index.
  151. ///
  152. /// @throw isc::OutOfRange if index is out of range.
  153. void writeBoolean(const bool value, const uint32_t index = 0);
  154. /// @brief Read a buffer as FQDN.
  155. ///
  156. /// @param index buffer index.
  157. ///
  158. /// @throw isc::OutOfRange if buffer index is out of range.
  159. /// @throw isc::dhcp::BadDataTypeCast if a buffer being read
  160. /// does not hold a valid FQDN.
  161. /// @return string representation if FQDN.
  162. std::string readFqdn(const uint32_t index = 0) const;
  163. /// @brief Write an FQDN into a buffer.
  164. ///
  165. /// @param fqdn text representation of FQDN.
  166. /// @param index buffer index.
  167. ///
  168. /// @throw isc::OutOfRange if index is out of range.
  169. void writeFqdn(const std::string& fqdn, const uint32_t index = 0);
  170. /// @brief Read a buffer as integer value.
  171. ///
  172. /// @param index buffer index.
  173. /// @tparam integer type of a value being returned.
  174. ///
  175. /// @throw isc::OutOfRange if index is out of range.
  176. /// @throw isc::dhcp::InvalidDataType if T is invalid.
  177. /// @return read integer value.
  178. template<typename T>
  179. T readInteger(const uint32_t index = 0) const {
  180. // Check that the index is not out of range.
  181. checkIndex(index);
  182. // Check that T points to a valid integer type and this type
  183. // is consistent with an option definition.
  184. checkDataType<T>(index);
  185. // When we created the buffer we have checked that it has a
  186. // valid size so this condition here should be always fulfilled.
  187. assert(buffers_[index].size() == OptionDataTypeTraits<T>::len);
  188. // Read an integer value.
  189. return (OptionDataTypeUtil::readInt<T>(buffers_[index]));
  190. }
  191. /// @brief Write an integer value into a buffer.
  192. ///
  193. /// @param value integer value to be written.
  194. /// @param index buffer index.
  195. /// @tparam T integer type of a value being written.
  196. ///
  197. /// @throw isc::OutOfRange if index is out of range.
  198. /// @throw isc::dhcp::InvalidDataType if T is invalid.
  199. template<typename T>
  200. void writeInteger(const T value, const uint32_t index = 0) {
  201. // Check that the index is not out of range.
  202. checkIndex(index);
  203. // Check that T points to a valid integer type and this type
  204. // is consistent with an option definition.
  205. checkDataType<T>(index);
  206. // Get some temporary buffer.
  207. OptionBuffer buf;
  208. // Try to write to the buffer.
  209. OptionDataTypeUtil::writeInt<T>(value, buf);
  210. // If successful, replace the old buffer with new one.
  211. std::swap(buffers_[index], buf);
  212. }
  213. /// @brief Read a buffer as string value.
  214. ///
  215. /// @param index buffer index.
  216. ///
  217. /// @return string value read from buffer.
  218. /// @throw isc::OutOfRange if index is out of range.
  219. std::string readString(const uint32_t index = 0) const;
  220. /// @brief Write a string value into a buffer.
  221. ///
  222. /// @param text the string value to be written.
  223. /// @param index buffer index.
  224. void writeString(const std::string& text,
  225. const uint32_t index = 0);
  226. /// @brief Writes DHCP option in a wire format to a buffer.
  227. ///
  228. /// @param buf output buffer (option will be stored there).
  229. virtual void pack(isc::util::OutputBuffer& buf);
  230. /// @brief Parses received buffer.
  231. ///
  232. /// @param begin iterator to first byte of option data
  233. /// @param end iterator to end of option data (first byte after option end)
  234. virtual void unpack(OptionBufferConstIter begin,
  235. OptionBufferConstIter end);
  236. /// @brief Returns string representation of the option.
  237. ///
  238. /// @param indent number of spaces before printed text.
  239. ///
  240. /// @return string with text representation.
  241. virtual std::string toText(int indent = 0);
  242. /// @brief Returns length of the complete option (data length +
  243. /// DHCPv4/DHCPv6 option header)
  244. ///
  245. /// @return length of the option
  246. virtual uint16_t len();
  247. /// @brief Sets content of this option from buffer.
  248. ///
  249. /// Option will be resized to length of buffer.
  250. ///
  251. /// @param first iterator pointing to beginning of buffer to copy.
  252. /// @param last iterator pointing to end of buffer to copy.
  253. void initialize(const OptionBufferConstIter first,
  254. const OptionBufferConstIter last);
  255. private:
  256. /// @brief Verify that the option comprises an array of values.
  257. ///
  258. /// This helper function is used by createArrayEntry functions
  259. /// and throws an exception if the particular option is not
  260. /// an array.
  261. ///
  262. /// @throw isc::InvalidOperation if option is not an array.
  263. inline void checkArrayType() const {
  264. if (!definition_.getArrayType()) {
  265. isc_throw(InvalidOperation, "failed to add new array entry to an"
  266. << " option. The option is not an array.");
  267. }
  268. }
  269. /// @brief Verify that the integer type is consistent with option
  270. /// field type.
  271. ///
  272. /// This convenience function checks that the data type specified as T
  273. /// is consistent with a type of a data field identified by index.
  274. ///
  275. /// @param index data field index.
  276. /// @tparam data type to be validated.
  277. ///
  278. /// @throw isc::dhcp::InvalidDataType if the type is invalid.
  279. template<typename T>
  280. // cppcheck-suppress unusedPrivateFunction
  281. void checkDataType(const uint32_t index) const;
  282. /// @brief Check if data field index is valid.
  283. ///
  284. /// @param index Data field index to check.
  285. ///
  286. /// @throw isc::OutOfRange if index is out of range.
  287. void checkIndex(const uint32_t index) const;
  288. /// @brief Create a collection of non initialized buffers.
  289. void createBuffers();
  290. /// @brief Create collection of buffers representing data field values.
  291. ///
  292. /// @param data_buf a buffer to be parsed.
  293. void createBuffers(const OptionBuffer& data_buf);
  294. /// @brief Return a text representation of a data field.
  295. ///
  296. /// @param data_type data type of a field.
  297. /// @param index data field buffer index within a custom option.
  298. ///
  299. /// @return text representation of a data field.
  300. std::string dataFieldToText(const OptionDataType data_type,
  301. const uint32_t index) const;
  302. /// Make this function private as we don't want it to be invoked
  303. /// on OptionCustom object. We rather want that initialize to
  304. /// be called instead.
  305. using Option::setData;
  306. /// Option definition used to create an option.
  307. OptionDefinition definition_;
  308. /// The collection of buffers holding data for option fields.
  309. /// The order of buffers corresponds to the order of option
  310. /// fields.
  311. std::vector<OptionBuffer> buffers_;
  312. };
  313. /// A pointer to the OptionCustom object.
  314. typedef boost::shared_ptr<OptionCustom> OptionCustomPtr;
  315. } // namespace isc::dhcp
  316. } // namespace isc
  317. #endif // OPTION_CUSTOM_H