option.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. // Copyright (C) 2011-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 OPTION_H
  15. #define OPTION_H
  16. #include <util/buffer.h>
  17. #include <boost/shared_ptr.hpp>
  18. #include <map>
  19. #include <string>
  20. #include <vector>
  21. namespace isc {
  22. namespace dhcp {
  23. /// @brief buffer types used in DHCP code.
  24. ///
  25. /// Dereferencing OptionBuffer iterator will point out to contiguous memory.
  26. typedef std::vector<uint8_t> OptionBuffer;
  27. /// iterator for walking over OptionBuffer
  28. typedef OptionBuffer::iterator OptionBufferIter;
  29. /// const_iterator for walking over OptionBuffer
  30. typedef OptionBuffer::const_iterator OptionBufferConstIter;
  31. /// pointer to a DHCP buffer
  32. typedef boost::shared_ptr<OptionBuffer> OptionBufferPtr;
  33. /// shared pointer to Option object
  34. class Option;
  35. typedef boost::shared_ptr<Option> OptionPtr;
  36. class Option {
  37. public:
  38. /// length of the usual DHCPv4 option header (there are exceptions)
  39. const static size_t OPTION4_HDR_LEN = 2;
  40. /// length of any DHCPv6 option header
  41. const static size_t OPTION6_HDR_LEN = 4;
  42. /// defines option universe DHCPv4 or DHCPv6
  43. enum Universe { V4, V6 };
  44. /// a collection of DHCPv6 options
  45. typedef std::multimap<unsigned int, OptionPtr> OptionCollection;
  46. /// @brief a factory function prototype
  47. ///
  48. /// @param u option universe (DHCPv4 or DHCPv6)
  49. /// @param type option type
  50. /// @param buf pointer to a buffer
  51. ///
  52. /// @todo Passing a separate buffer for each option means that a copy
  53. /// was done. We can avoid it by passing 2 iterators.
  54. ///
  55. /// @return a pointer to a created option object
  56. typedef OptionPtr Factory(Option::Universe u, uint16_t type, const OptionBuffer& buf);
  57. /// @brief Factory function to create instance of option.
  58. ///
  59. /// Factory method creates instance of specified option. The option
  60. /// to be created has to have corresponding factory function
  61. /// registered with \ref LibDHCP::OptionFactoryRegister.
  62. ///
  63. /// @param u universe of the option (V4 or V6)
  64. /// @param type option-type
  65. /// @param buf option-buffer
  66. ///
  67. /// @return instance of option.
  68. ///
  69. /// @throw isc::InvalidOperation if there is no factory function
  70. /// registered for specified option type.
  71. static OptionPtr factory(Option::Universe u,
  72. uint16_t type,
  73. const OptionBuffer& buf);
  74. /// @brief Factory function to create instance of option.
  75. ///
  76. /// Factory method creates instance of specified option. The option
  77. /// to be created has to have corresponding factory function
  78. /// registered with \ref LibDHCP::OptionFactoryRegister.
  79. /// This method creates empty \ref OptionBuffer object. Use this
  80. /// factory function if it is not needed to pass custom buffer.
  81. ///
  82. /// @param u universe of the option (V4 or V6)
  83. /// @param type option-type
  84. ///
  85. /// @return instance of option.
  86. ///
  87. /// @throw isc::InvalidOperation if there is no factory function
  88. /// registered for specified option type.
  89. static OptionPtr factory(Option::Universe u, uint16_t type) {
  90. return factory(u, type, OptionBuffer());
  91. }
  92. /// @brief ctor, used for options constructed, usually during transmission
  93. ///
  94. /// @param u option universe (DHCPv4 or DHCPv6)
  95. /// @param type option type
  96. Option(Universe u, uint16_t type);
  97. /// @brief Constructor, used for received options.
  98. ///
  99. /// This constructor takes vector<uint8_t>& which is used in cases
  100. /// when content of the option will be copied and stored within
  101. /// option object. V4 Options follow that approach already.
  102. /// @todo Migrate V6 options to that approach.
  103. ///
  104. /// @param u specifies universe (V4 or V6)
  105. /// @param type option type (0-255 for V4 and 0-65535 for V6)
  106. /// @param data content of the option
  107. Option(Universe u, uint16_t type, const OptionBuffer& data);
  108. /// @brief Constructor, used for received options.
  109. ///
  110. /// This contructor is similar to the previous one, but it does not take
  111. /// the whole vector<uint8_t>, but rather subset of it.
  112. ///
  113. /// @todo This can be templated to use different containers, not just
  114. /// vector. Prototype should look like this:
  115. /// template<typename InputIterator> Option(Universe u, uint16_t type,
  116. /// InputIterator first, InputIterator last);
  117. ///
  118. /// vector<int8_t> myData;
  119. /// Example usage: new Option(V4, 123, myData.begin()+1, myData.end()-1)
  120. /// This will create DHCPv4 option of type 123 that contains data from
  121. /// trimmed (first and last byte removed) myData vector.
  122. ///
  123. /// @param u specifies universe (V4 or V6)
  124. /// @param type option type (0-255 for V4 and 0-65535 for V6)
  125. /// @param first iterator to the first element that should be copied
  126. /// @param last iterator to the next element after the last one
  127. /// to be copied.
  128. Option(Universe u, uint16_t type, OptionBufferConstIter first,
  129. OptionBufferConstIter last);
  130. /// @brief returns option universe (V4 or V6)
  131. ///
  132. /// @return universe type
  133. Universe getUniverse() const { return universe_; };
  134. /// @brief Writes option in wire-format to a buffer.
  135. ///
  136. /// Writes option in wire-format to buffer, returns pointer to first unused
  137. /// byte after stored option (that is useful for writing options one after
  138. /// another). Used in DHCPv6 options.
  139. ///
  140. /// @todo Migrate DHCPv6 code to pack(OutputBuffer& buf) version
  141. ///
  142. /// @param buf pointer to a buffer
  143. ///
  144. /// @throw BadValue Universe of the option is neither V4 nor V6.
  145. virtual void pack(isc::util::OutputBuffer& buf);
  146. /// @brief Writes option in a wire-format to a buffer.
  147. ///
  148. /// Method will throw if option storing fails for some reason.
  149. ///
  150. /// @todo Once old (DHCPv6) implementation is rewritten,
  151. /// unify pack4() and pack6() and rename them to just pack().
  152. ///
  153. /// @param buf output buffer (option will be stored there)
  154. ///
  155. /// @throw OutOfRange Option type is greater than 255.
  156. /// @throw BadValue Universe is not V4.
  157. virtual void pack4(isc::util::OutputBuffer& buf);
  158. /// @brief Parses received buffer.
  159. ///
  160. /// @param begin iterator to first byte of option data
  161. /// @param end iterator to end of option data (first byte after option end)
  162. virtual void unpack(OptionBufferConstIter begin,
  163. OptionBufferConstIter end);
  164. /// Returns string representation of the option.
  165. ///
  166. /// @param indent number of spaces before printing text
  167. ///
  168. /// @return string with text representation.
  169. virtual std::string toText(int indent = 0);
  170. /// Returns option type (0-255 for DHCPv4, 0-65535 for DHCPv6)
  171. ///
  172. /// @return option type
  173. uint16_t getType() const { return (type_); }
  174. /// Returns length of the complete option (data length + DHCPv4/DHCPv6
  175. /// option header)
  176. ///
  177. /// @return length of the option
  178. virtual uint16_t len();
  179. /// @brief Returns length of header (2 for v4, 4 for v6)
  180. ///
  181. /// @return length of option header
  182. virtual uint16_t getHeaderLen();
  183. /// returns if option is valid (e.g. option may be truncated)
  184. ///
  185. /// @return true, if option is valid
  186. virtual bool valid();
  187. /// Returns pointer to actual data.
  188. ///
  189. /// @return pointer to actual data (or reference to an empty vector
  190. /// if there is no data)
  191. virtual const OptionBuffer& getData() const { return (data_); }
  192. /// Adds a sub-option.
  193. ///
  194. /// Some DHCPv6 options can have suboptions. This method allows adding
  195. /// options within options.
  196. ///
  197. /// Note: option is passed by value. That is very convenient as it allows
  198. /// downcasting from any derived classes, e.g. shared_ptr<Option6_IA> type
  199. /// can be passed directly, without any casts. That would not be possible
  200. /// with passing by reference. addOption() is expected to be used in
  201. /// many places. Requiring casting is not feasible.
  202. ///
  203. /// @param opt shared pointer to a suboption that is going to be added.
  204. void addOption(OptionPtr opt);
  205. /// Returns shared_ptr to suboption of specific type
  206. ///
  207. /// @param type type of requested suboption
  208. ///
  209. /// @return shared_ptr to requested suoption
  210. OptionPtr getOption(uint16_t type);
  211. /// Attempts to delete first suboption of requested type
  212. ///
  213. /// @param type Type of option to be deleted.
  214. ///
  215. /// @return true if option was deleted, false if no such option existed
  216. bool delOption(uint16_t type);
  217. /// @brief Returns content of first byte.
  218. ///
  219. /// @throw isc::OutOfRange Thrown if the option has a length of 0.
  220. ///
  221. /// @return value of the first byte
  222. uint8_t getUint8();
  223. /// @brief Returns content of first word.
  224. ///
  225. /// @throw isc::OutOfRange Thrown if the option has a length less than 2.
  226. ///
  227. /// @return uint16_t value stored on first two bytes
  228. uint16_t getUint16();
  229. /// @brief Returns content of first double word.
  230. ///
  231. /// @throw isc::OutOfRange Thrown if the option has a length less than 4.
  232. ///
  233. /// @return uint32_t value stored on first four bytes
  234. uint32_t getUint32();
  235. /// @brief Sets content of this option to singe uint8 value.
  236. ///
  237. /// Option it resized appropriately (to length of 1 octet).
  238. ///
  239. /// @param value value to be set
  240. void setUint8(uint8_t value);
  241. /// @brief Sets content of this option to singe uint16 value.
  242. ///
  243. /// Option it resized appropriately (to length of 2 octets).
  244. ///
  245. /// @param value value to be set
  246. void setUint16(uint16_t value);
  247. /// @brief Sets content of this option to singe uint32 value.
  248. ///
  249. /// Option it resized appropriately (to length of 4 octets).
  250. ///
  251. /// @param value value to be set
  252. void setUint32(uint32_t value);
  253. /// @brief Sets content of this option from buffer.
  254. ///
  255. /// Option will be resized to length of buffer.
  256. ///
  257. /// @param first iterator pointing begining of buffer to copy.
  258. /// @param last iterator pointing to end of buffer to copy.
  259. void setData(const OptionBufferConstIter first,
  260. const OptionBufferConstIter last);
  261. /// just to force that every option has virtual dtor
  262. virtual ~Option();
  263. /// @brief Checks if two options are equal
  264. ///
  265. /// Equality verifies option type and option content. Care should
  266. /// be taken when using this method. Implementation for derived
  267. /// classes should be provided when this method is expected to be
  268. /// used. It is safe in general, as the first check (different types)
  269. /// will detect differences between base Option and derived
  270. /// objects.
  271. ///
  272. /// @param other the other option
  273. /// @return true if both options are equal
  274. virtual bool equal(const OptionPtr& other) const;
  275. protected:
  276. /// Builds raw (over-wire) buffer of this option, including all
  277. /// defined suboptions. Version for building DHCPv4 options.
  278. ///
  279. /// @param buf output buffer (built options will be stored here)
  280. ///
  281. /// @throw BadValue Universe is not V6.
  282. virtual void pack6(isc::util::OutputBuffer& buf);
  283. /// @brief Store option's header in a buffer.
  284. ///
  285. /// This method writes option's header into a buffer in the
  286. /// on-wire format. The universe set for the particular option
  287. /// is used to determine whether option code and length are
  288. /// stored as 2-byte (for DHCPv6) or single-byte (for DHCPv4)
  289. /// values. For DHCPv4 options, this method checks if the
  290. /// length does not exceed 255 bytes and throws exception if
  291. /// it does.
  292. /// This method is used by derived classes to pack option's
  293. /// header into a buffer. This method should not be called
  294. /// directly by other classes.
  295. ///
  296. /// @param [out] buf output buffer.
  297. void packHeader(isc::util::OutputBuffer& buf);
  298. /// @brief Store sub options in a buffer.
  299. ///
  300. /// This method stores all sub-options defined for a particular
  301. /// option in a on-wire format in output buffer provided.
  302. /// This function is called by pack function in this class or
  303. /// derived classes that override pack.
  304. ///
  305. /// @param [out] buf output buffer.
  306. ///
  307. /// @todo The set of exceptions thrown by this function depend on
  308. /// exceptions thrown by pack methods invoked on objects
  309. /// representing sub options. We should consider whether to aggregate
  310. /// those into one exception which can be documented here.
  311. void packOptions(isc::util::OutputBuffer& buf);
  312. /// @brief Builds a collection of sub options from the buffer.
  313. ///
  314. /// This method parses the provided buffer and builds a collection
  315. /// of objects representing sub options. This function may throw
  316. /// different exceptions when option assembly fails.
  317. ///
  318. /// @param buf buffer to be parsed.
  319. ///
  320. /// @todo The set of exceptions thrown by this function depend on
  321. /// exceptions thrown by unpack methods invoked on objects
  322. /// representing sub options. We should consider whether to aggregate
  323. /// those into one exception which can be documented here.
  324. void unpackOptions(const OptionBuffer& buf);
  325. /// @brief A private method used for option correctness.
  326. ///
  327. /// It is used in constructors. In there are any problems detected
  328. /// (like specifying type > 255 for DHCPv4 option), it will throw
  329. /// BadValue or OutOfRange exceptions.
  330. void check();
  331. /// option universe (V4 or V6)
  332. Universe universe_;
  333. /// option type (0-255 for DHCPv4, 0-65535 for DHCPv6)
  334. uint16_t type_;
  335. /// contains content of this data
  336. OptionBuffer data_;
  337. /// collection for storing suboptions
  338. OptionCollection options_;
  339. /// @todo probably 2 different containers have to be used for v4 (unique
  340. /// options) and v6 (options with the same type can repeat)
  341. };
  342. } // namespace isc::dhcp
  343. } // namespace isc
  344. #endif // OPTION_H