diff options
Diffstat (limited to '')
-rw-r--r-- | src/lib/dhcpsrv/cfg_option.h | 816 |
1 files changed, 816 insertions, 0 deletions
diff --git a/src/lib/dhcpsrv/cfg_option.h b/src/lib/dhcpsrv/cfg_option.h new file mode 100644 index 0000000..a0c6d0b --- /dev/null +++ b/src/lib/dhcpsrv/cfg_option.h @@ -0,0 +1,816 @@ +// Copyright (C) 2014-2023 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef CFG_OPTION_H +#define CFG_OPTION_H + +#include <dhcp/option.h> +#include <dhcp/option_space_container.h> +#include <cc/cfg_to_element.h> +#include <cc/stamped_element.h> +#include <cc/user_context.h> +#include <dhcpsrv/cfg_option_def.h> +#include <dhcpsrv/key_from_key.h> +#include <boost/multi_index_container.hpp> +#include <boost/multi_index/hashed_index.hpp> +#include <boost/multi_index/ordered_index.hpp> +#include <boost/multi_index/sequenced_index.hpp> +#include <boost/multi_index/mem_fun.hpp> +#include <boost/multi_index/member.hpp> +#include <boost/shared_ptr.hpp> +#include <stdint.h> +#include <list> +#include <string> +#include <vector> + +namespace isc { +namespace dhcp { + +class OptionDescriptor; + +/// A pointer to option descriptor. +typedef boost::shared_ptr<OptionDescriptor> OptionDescriptorPtr; + +/// A list of option descriptors. +typedef std::vector<OptionDescriptor> OptionDescriptorList; + +/// @brief Option descriptor. +/// +/// Option descriptor holds instance of an option and additional information +/// for this option. This information comprises whether this option is sent +/// to DHCP client only on request (persistent = false) or always +/// (persistent = true), or must never send (cancelled = true). +class OptionDescriptor : public data::StampedElement, public data::UserContext { +public: + /// @brief Option instance. + OptionPtr option_; + + /// @brief Persistence flag. + /// + /// If true, option is always sent to the client. If false, option is + /// sent to the client when requested using ORO or PRL option. + bool persistent_; + + /// @brief Cancelled flag. + /// + /// If true, option is never sent to the client. If false, option is + /// sent when it should. + /// @note: When true the action of this flag is final i.e. it can't be + /// overridden at a more specific level and has precedence over persist. + bool cancelled_; + + /// @brief Option value in textual (CSV) format. + /// + /// This field is used to convey option value in human readable format, + /// the same as used to specify option value in the server configuration. + /// This value is optional and can be held in the host reservations + /// database instead of the binary format. + /// + /// Note that this value is carried in the option descriptor, rather than + /// @c Option instance because it is a server specific value (same as + /// persistence flag). + /// + /// An example of the formatted value is: "2001:db8:1::1, 23, some text" + /// for the option which carries IPv6 address, a number and a text. + std::string formatted_value_; + + /// @brief Option space name. + /// + /// Options are associated with option spaces. Typically, such association + /// is made when the option is stored in the @c OptionContainer. However, + /// in some cases it is also required to associate option with the particular + /// option space outside of the container. In particular, when the option + /// is fetched from a database. The database configuration backend will + /// set option space upon return of the option. In other cases this value + /// won't be set. + std::string space_name_; + + /// @brief Constructor. + /// + /// @param opt option instance. + /// @param persist if true, option is always sent. + /// @param cancel if true, option is never sent. + /// @param formatted_value option value in the textual format (optional). + /// @param user_context user context (optional). + OptionDescriptor(const OptionPtr& opt, bool persist, bool cancel, + const std::string& formatted_value = "", + data::ConstElementPtr user_context = data::ConstElementPtr()) + : data::StampedElement(), option_(opt), persistent_(persist), + cancelled_(cancel), formatted_value_(formatted_value), + space_name_() { + setContext(user_context); + }; + + /// @brief Constructor. + /// + /// @param persist if true option is always sent. + /// @param cancel if true, option is never sent. + OptionDescriptor(bool persist, bool cancel) + : data::StampedElement(), option_(OptionPtr()), persistent_(persist), + cancelled_(cancel), formatted_value_(), space_name_() {}; + + /// @brief Copy constructor. + /// + /// @param desc option descriptor to be copied. + OptionDescriptor(const OptionDescriptor& desc) + : data::StampedElement(desc), + option_(desc.option_), + persistent_(desc.persistent_), + cancelled_(desc.cancelled_), + formatted_value_(desc.formatted_value_), + space_name_(desc.space_name_) { + setContext(desc.getContext()); + }; + + /// @brief Assignment operator. + /// + /// @param other option descriptor to be assigned from. + OptionDescriptor& operator=(const OptionDescriptor& other) { + if (this != &other) { + // Not self-assignment. + data::StampedElement::operator=(other); + option_ = other.option_; + persistent_ = other.persistent_; + cancelled_ = other.cancelled_; + formatted_value_ = other.formatted_value_; + space_name_ = other.space_name_; + setContext(other.getContext()); + } + return (*this); + } + + /// @brief Factory function creating an instance of the @c OptionDescriptor. + /// + /// @param opt option instance. + /// @param persist if true, option is always sent. + /// @param cancel if true, option is never sent. + /// @param formatted_value option value in the textual format (optional). + /// @param user_context user context (optional). + /// + /// @return Pointer to the @c OptionDescriptor instance. + static OptionDescriptorPtr create(const OptionPtr& opt, + bool persist, + bool cancel, + const std::string& formatted_value = "", + data::ConstElementPtr user_context = + data::ConstElementPtr()); + + /// @brief Factory function creating an instance of the @c OptionDescriptor. + /// + /// @param persist if true option is always sent. + /// @param cancel if true, option is never sent. + /// + /// @return Pointer to the @c OptionDescriptor instance. + static OptionDescriptorPtr create(bool persist, bool cancel); + + /// @brief Factory function creating an instance of the @c OptionDescriptor. + /// + /// @param desc option descriptor to be copied. + /// + /// @return Pointer to the @c OptionDescriptor instance. + static OptionDescriptorPtr create(const OptionDescriptor& desc); + + /// @brief Checks if the one descriptor is equal to another. + /// + /// @param other Other option descriptor to compare to. + /// + /// @return true if descriptors equal, false otherwise. + bool equals(const OptionDescriptor& other) const; + + /// @brief Equality operator. + /// + /// @param other Other option descriptor to compare to. + /// + /// @return true if descriptors equal, false otherwise. + bool operator==(const OptionDescriptor& other) const { + return (equals(other)); + } + + /// @brief Inequality operator. + /// + /// @param other Other option descriptor to compare to. + /// + /// @return true if descriptors unequal, false otherwise. + bool operator!=(const OptionDescriptor& other) const { + return (!equals(other)); + } +}; + +/// @brief Multi index container for DHCP option descriptors. +/// +/// This container comprises three indexes to access option +/// descriptors: +/// - sequenced index: used to access elements in the order they +/// have been added to the container, +/// - option type index: used to search option descriptors containing +/// options with specific option code (aka option type). +/// - persistency flag index: used to search option descriptors with +/// 'persistent' flag set to true. +/// +/// This container is the equivalent of four separate STL containers: +/// - std::list of all options, +/// - std::multimap of options with option code used as a multimap key, +/// - std::multimap of option descriptors with option persistency flag +/// used as a multimap key. +/// - std::multimap of option descriptors with option cancellation flag +/// used as a multimap key. +/// The major advantage of this container over 4 separate STL containers +/// is automatic synchronization of all indexes when elements are added, +/// removed or modified in the container. With separate containers, +/// the synchronization would have to be guaranteed by the Subnet class +/// code. This would increase code complexity and presumably it would +/// be much harder to add new search criteria (indexes). +/// +/// @todo we may want to search for options using option spaces when +/// they are implemented. +/// +/// @see http://www.boost.org/doc/libs/1_51_0/libs/multi_index/doc/index.html +typedef boost::multi_index_container< + // Container comprises elements of OptionDescriptor type. + OptionDescriptor, + // Here we start enumerating various indexes. + boost::multi_index::indexed_by< + // Sequenced index allows accessing elements in the same way + // as elements in std::list. + // Sequenced is an index #0. + boost::multi_index::sequenced<>, + // Start definition of index #1. + boost::multi_index::hashed_non_unique< + // KeyFromKeyExtractor is the index key extractor that allows + // accessing option type being held by the OptionPtr through + // OptionDescriptor structure. + KeyFromKeyExtractor< + // Use option type as the index key. The type is held + // in OptionPtr object so we have to call Option::getType + // to retrieve this key for each element. + boost::multi_index::const_mem_fun< + Option, + uint16_t, + &Option::getType + >, + // Indicate that OptionPtr is a member of + // OptionDescriptor structure. + boost::multi_index::member< + OptionDescriptor, + OptionPtr, + &OptionDescriptor::option_ + > + > + >, + // Start definition of index #2. + // Use 'persistent' struct member as a key. + boost::multi_index::hashed_non_unique< + boost::multi_index::member< + OptionDescriptor, + bool, + &OptionDescriptor::persistent_ + > + >, + // Start definition of index #3. + // Use BaseStampedElement::getModificationTime as a key. + boost::multi_index::ordered_non_unique< + boost::multi_index::const_mem_fun< + data::BaseStampedElement, + boost::posix_time::ptime, + &data::BaseStampedElement::getModificationTime + > + >, + + // Start definition of index #4. + // Use BaseStampedElement::getId as a key. + boost::multi_index::hashed_non_unique< + boost::multi_index::tag<OptionIdIndexTag>, + boost::multi_index::const_mem_fun<data::BaseStampedElement, uint64_t, + &data::BaseStampedElement::getId> + >, + // Start definition of index #5. + // Use 'cancelled' struct member as a key. + boost::multi_index::hashed_non_unique< + boost::multi_index::member< + OptionDescriptor, + bool, + &OptionDescriptor::cancelled_ + > + > + > +> OptionContainer; + +/// Pointer to the OptionContainer object. +typedef boost::shared_ptr<OptionContainer> OptionContainerPtr; +/// Type of the index #1 - option type. +typedef OptionContainer::nth_index<1>::type OptionContainerTypeIndex; +/// Pair of iterators to represent the range of options having the +/// same option type value. The first element in this pair represents +/// the beginning of the range, the second element represents the end. +typedef std::pair<OptionContainerTypeIndex::const_iterator, + OptionContainerTypeIndex::const_iterator> OptionContainerTypeRange; +/// Type of the index #2 - option persistency flag. +typedef OptionContainer::nth_index<2>::type OptionContainerPersistIndex; +/// Pair of iterators to represent the range of options having the +/// same persistency flag. The first element in this pair represents +/// the beginning of the range, the second element represents the end. +typedef std::pair<OptionContainerPersistIndex::const_iterator, + OptionContainerPersistIndex::const_iterator> OptionContainerPersistRange; +/// Type of the index #5 - option cancellation flag. +typedef OptionContainer::nth_index<5>::type OptionContainerCancelIndex; +/// Pair of iterators to represent the range of options having the +/// same cancellation flag. The first element in this pair represents +/// the beginning of the range, the second element represents the end. +typedef std::pair<OptionContainerCancelIndex::const_iterator, + OptionContainerCancelIndex::const_iterator> OptionContainerCancelRange; + +/// @brief Represents option data configuration for the DHCP server. +/// +/// This class holds a collection of options to be sent to a DHCP client. +/// Options are grouped by the option space or vendor identifier (for +/// vendor options). +/// +/// The server configuration allows for specifying two distinct collections +/// of options: global options and per-subnet options in which some options +/// may overlap. +/// +/// The collection of global options specify options being sent to the client +/// belonging to any subnets, i.e. global options are "inherited" by all +/// subnets. +/// +/// The per-subnet options are configured for a particular subnet and are sent +/// to clients which belong to this subnet. The values of the options specified +/// for a particular subnet override the values of the global options. +/// +/// This class represents a single collection of options (either global or +/// per-subnet). Each subnet holds its own object of the @c CfgOption type. The +/// @c CfgMgr holds a @c CfgOption object representing global options. +/// +/// Note that having a separate copy of the @c CfgOption to represent global +/// options is useful when the client requests stateless configuration from +/// the DHCP server and no subnet is selected for this client. This client +/// will only receive global options. +class CfgOption : public isc::data::CfgToElement { +public: + + /// @brief default constructor + CfgOption(); + + /// @brief Indicates the object is empty + /// + /// @return true when the object is empty + bool empty() const; + + /// @name Methods and operators used for comparing objects. + /// + //@{ + /// @brief Check if configuration is equal to other configuration. + /// + /// @param other An object holding configuration to compare to. + /// + /// @return true if configurations are equal, false otherwise. + bool equals(const CfgOption& other) const; + + /// @brief Equality operator. + /// + /// @param other An object holding configuration to compare to. + /// + /// @return true if configurations are equal, false otherwise. + bool operator==(const CfgOption& other) const { + return (equals(other)); + } + + /// @brief Inequality operator. + /// + /// @param other An object holding configuration to compare to. + /// + /// @return true if configurations are unequal, false otherwise. + bool operator!=(const CfgOption& other) const { + return (!equals(other)); + } + + //@} + + /// @brief Adds instance of the option to the configuration. + /// + /// There are two types of options which may be passed to this method: + /// - vendor options + /// - non-vendor options + /// + /// The non-vendor options are grouped by the name of the option space + /// (specified in textual format). The vendor options are grouped by the + /// vendor identifier, which is a 32-bit unsigned integer value. + /// + /// In order to add new vendor option to the list the option space name + /// (last argument of this method) should be specified as "vendor-X" where + /// "X" is a 32-bit unsigned integer, e.g. "vendor-1234". Options for which + /// the @c option_space argument doesn't follow this format are added as + /// non-vendor options. + /// + /// @param option Pointer to the option being added. + /// @param persistent Boolean value which specifies if the option should + /// be sent to the client regardless if requested (true), or nor (false) + /// @param cancelled Boolean value which specifies if the option must + /// never be sent to the client. + /// @param option_space Option space name. + /// @param id Optional database id to be associated with the option. + /// + /// @throw isc::BadValue if the option space is invalid. + void add(const OptionPtr& option, const bool persistent, + const bool cancelled, const std::string& option_space, + const uint64_t id = 0); + + /// @brief A variant of the @ref CfgOption::add method which takes option + /// descriptor as an argument. + /// + /// @param desc Option descriptor holding option instance and other + /// parameters pertaining to the option. + /// @param option_space Option space name. + /// + /// @throw isc::BadValue if the option space is invalid. + void add(const OptionDescriptor& desc, const std::string& option_space); + + /// @brief Replaces the instance of an option within this collection + /// + /// This method locates the option within the given space and replaces + /// it with a copy of the given descriptor. This effectively updates + /// the contents without altering the container indexing. + /// + /// @param desc Option descriptor holding option instance and other + /// parameters pertaining to the option. + /// @param option_space Option space name. + /// + /// @throw isc::BadValue if the descriptor's option instance is null, + /// if space is invalid, or if the option does not already exist + /// in the given space. + void replace(const OptionDescriptor& desc, const std::string& option_space); + + /// @brief Merges another option configuration into this one. + /// + /// This method calls @c mergeTo() to add this configuration's + /// options into @c other (skipping any duplicates). Next it calls + /// @c createDescriptorOption() for each option descriptor in the + /// merged set. This (re)-creates each descriptor's option based on + /// the merged set of opt definitions. Finally, it calls + /// @c copyTo() to overwrite this configuration's options with + /// the merged set in @c other. + /// + /// @warning The merge operation will affect the @c other configuration. + /// Therefore, the caller must not rely on the data held in the @c other + /// object after the call to @c merge. Also, the data held in @c other must + /// not be modified after the call to @c merge because it may affect the + /// merged configuration. + /// + /// @param cfg_def set of of user-defined option definitions to use + /// when merging. + /// @param other option configuration to merge in. + void merge(CfgOptionDefPtr cfg_def, CfgOption& other); + + /// @brief Re-create the option in each descriptor based on given definitions + /// + /// Invokes @c createDescriptorOption() on each option descriptor in + /// each option space, passing in the given dictionary of option + /// definitions. If the descriptor's option is re-created, then the + /// descriptor is updated by calling @c replace(). + /// + /// @param cfg_def set of of user-defined option definitions to use + /// when creating option instances. + void createOptions(CfgOptionDefPtr cfg_def); + + /// @brief Creates an option descriptor's option based on a set of option defs + /// + /// This function's primary use is to create definition specific options for + /// option descriptors fetched from a configuration backend, as part of a + /// configuration merge. + /// + /// Given an OptionDescriptor whose option_ member contains a generic option + /// (i.e has a code and/or data), this function will attempt to find a matching + /// definition and then use that definition's factory to create an option + /// instance specific to that definition. It will then replace the descriptor's + /// generic option with the specific option. + /// + /// Three sources of definitions are searched, in the following order: + /// + /// 1. Standard option definitions (@c LIBDHCP::getOptionDef)) + /// 2. Vendor option definitions (@c LIBDHCP::getVendorOptionDef)) + /// 3. User specified definitions passed in via cfg_def parameter. + /// + /// The code will use the first matching definition found. It then applies + /// the following rules: + /// + /// -# If no definition is found but the descriptor conveys a non-empty + /// formatted value, throw an error. + /// -# If not definition is found and there is no formatted value, return + /// This leaves intact the generic option in the descriptor. + /// -# If a definition is found and there is no formatted value, pass the + /// descriptor's generic option's data into the definition's factory. Replace + /// the descriptor's option with the newly created option. + /// -# If a definition is found and there is a formatted value, split + /// the value into vector of values and pass that into the definition's + /// factory. Replace the descriptor's option with the newly created option. + /// + /// @param cfg_def the user specified definitions to use + /// @param space the option space name of the option + /// @param opt_desc OptionDescriptor describing the option. + /// + /// @return True if the descriptor's option instance was replaced. + /// @throw InvalidOperation if the descriptor conveys a formatted value and + /// there is no definition matching the option code in the given space, or + /// if the definition factory invocation fails. + static bool createDescriptorOption(CfgOptionDefPtr cfg_def, const std::string& space, + OptionDescriptor& opt_desc); + + /// @brief Merges this configuration to another configuration. + /// + /// This method iterates over the configuration items held in this + /// configuration and copies them to the configuration specified + /// as a parameter. If an item exists in the destination it is not + /// copied. + /// + /// @param [out] other Configuration object to merge to. + void mergeTo(CfgOption& other) const; + + /// @brief Copies this configuration to another configuration. + /// + /// This method copies options configuration to another object. + /// + /// @param [out] other An object to copy the configuration to. + void copyTo(CfgOption& other) const; + + /// @brief Appends encapsulated options to top-level options. + /// + /// This method iterates over the top-level options (from "dhcp4" + /// and "dhcp6" option space) and checks which option spaces these + /// options encapsulate. For each encapsulated option space, the + /// options from this option space are appended to top-level options. + void encapsulate(); + + /// @brief Checks if options have been encapsulated. + /// + /// @return true if options have been encapsulated, false otherwise. + bool isEncapsulated() const { + return (encapsulated_); + } + + /// @brief Returns all options for the specified option space. + /// + /// This method will not return vendor options, i.e. having option space + /// name in the format of "vendor-X" where X is 32-bit unsigned integer. + /// See @c getAll(uint32_t) for vendor options. + /// + /// @param option_space Name of the option space. + /// + /// @return Pointer to the container holding returned options. This + /// container is empty if no options have been found. + OptionContainerPtr getAll(const std::string& option_space) const; + + /// @brief Returns vendor options for the specified vendor id. + /// + /// @param vendor_id Vendor id for which options are to be returned. + /// + /// @return Pointer to the container holding returned options. This + /// container is empty if no options have been found. + OptionContainerPtr getAll(const uint32_t vendor_id) const; + + /// @brief Returns all non-vendor or vendor options for the specified + /// option space. + /// + /// It combines the output of the @c getAll function variants. When + /// option space has the format of "vendor-X", it retrieves the vendor + /// options by vendor id, where X must be a 32-bit unsigned integer. + /// Otherwise, it fetches non-vendor options. + /// + /// @param option_space Name of the option space. + /// @return Pointer to the container holding returned options. This + /// container is empty if no options have been found. + OptionContainerPtr getAllCombined(const std::string& option_space) const; + + /// @brief Returns option for the specified key and option code. + /// + /// The key should be a string, in which case it specifies an option space + /// name, or an uint32_t value, in which case it specifies a vendor + /// identifier. + /// + /// @note If there are multiple options with the same key, only one will + /// be returned. No indication will be given of the presence of others, + /// and the instance returned is not determinable. So please use + /// the next method when multiple instances of the option are expected. + /// + /// @param key Option space name or vendor identifier. + /// @param option_code Code of the option to be returned. + /// @tparam Selector one of: @c std::string or @c uint32_t + /// + /// @return Descriptor of the option. If option hasn't been found, the + /// descriptor holds null option. + template<typename Selector> + OptionDescriptor get(const Selector& key, + const uint16_t option_code) const { + + // Check for presence of options. + OptionContainerPtr options = getAll(key); + if (!options || options->empty()) { + return (OptionDescriptor(false, false)); + } + + // Some options present, locate the one we are interested in. + const OptionContainerTypeIndex& idx = options->get<1>(); + OptionContainerTypeIndex::const_iterator od_itr = idx.find(option_code); + if (od_itr == idx.end()) { + return (OptionDescriptor(false, false)); + } + + return (*od_itr); + } + + /// @brief Returns options for the specified key and option code. + /// + /// The key should be a string, in which case it specifies an option space + /// name, or an uint32_t value, in which case it specifies a vendor + /// identifier. + /// + /// @param key Option space name or vendor identifier. + /// @param option_code Code of the option to be returned. + /// @tparam Selector one of: @c std::string or @c uint32_t + /// + /// @return List of Descriptors of the option. + template<typename Selector> + OptionDescriptorList getList(const Selector& key, + const uint16_t option_code) const { + + OptionDescriptorList list; + // Check for presence of options. + OptionContainerPtr options = getAll(key); + if (!options || options->empty()) { + return (list); + } + + // Some options present, locate the one we are interested in. + const OptionContainerTypeIndex& idx = options->get<1>(); + OptionContainerTypeRange range = idx.equal_range(option_code); + // This code copies descriptors and can be optimized not doing this. + for (OptionContainerTypeIndex::const_iterator od_itr = range.first; + od_itr != range.second; ++od_itr) { + list.push_back(*od_itr); + } + + return (list); + } + + /// @brief Deletes option for the specified option space and option code. + /// + /// If the option is encapsulated within some non top level option space, + /// it is also deleted from all option instances encapsulating this + /// option space. + /// + /// @param option_space Option space name. + /// @param option_code Code of the option to be returned. + /// + /// @return Number of deleted options. + size_t del(const std::string& option_space, const uint16_t option_code); + + /// @brief Deletes vendor option for the specified vendor id. + /// + /// @param vendor_id Vendor identifier. + /// @param option_code Option code. + /// + /// @return Number of deleted options. + size_t del(const uint32_t vendor_id, const uint16_t option_code); + + /// @brief Deletes all options having a given database id. + /// + /// Note that there are cases when there will be multiple options + /// having the same id (typically id of 0). When configuration backend + /// is in use it sets the unique ids from the database. In cases when + /// the configuration backend is not used, the ids default to 0. + /// Passing the id of 0 would result in deleting all options that were + /// not added via the database. + /// + /// Both regular and vendor specific options are deleted with this + /// method. + /// + /// This method internally calls @c encapsulate() after deleting + /// options having the given id. + /// + /// @param id Identifier of the options to be deleted. + /// + /// @return Number of deleted options. Note that if a single option + /// instance is encapsulated by multiple options it adds 1 to the + /// number of deleted options even though the same instance is + /// deleted from multiple higher level options. + size_t del(const uint64_t id); + + /// @brief Returns a list of configured option space names. + /// + /// The returned option space names exclude vendor option spaces, + /// such as "vendor-1234". These are returned by the + /// @ref getVendorIdsSpaceNames. + /// + /// @return List comprising option space names. + std::list<std::string> getOptionSpaceNames() const { + return (options_.getOptionSpaceNames()); + } + + /// @brief Returns a list of all configured vendor identifiers. + std::list<uint32_t> getVendorIds() const { + return (vendor_options_.getOptionSpaceNames()); + } + + /// @brief Returns a list of option space names for configured vendor ids. + /// + /// For each vendor-id the option space name returned is constructed + /// as "vendor-XYZ" where XYZ is a @c uint32_t value without leading + /// zeros. + /// + /// @return List comprising option space names for vendor options. + std::list<std::string> getVendorIdsSpaceNames() const; + + /// @brief Unparse a configuration object + /// + /// @return a pointer to unparsed configuration + virtual isc::data::ElementPtr toElement() const; + + /// @brief Unparse a configuration object with optionally including + /// the metadata. + /// + /// @param include_metadata boolean value indicating if the metadata + /// should be included (if true) or not (if false). + /// + /// @return A pointer to the unparsed configuration. + isc::data::ElementPtr + toElementWithMetadata(const bool include_metadata) const; + +private: + + /// @brief Appends encapsulated options to the options in an option space. + /// + /// This method appends sub-options to the options belonging to the + /// particular option space. For example: if the option space "foo" + /// is specified, this function will go over all options belonging to + /// "foo" and will check which option spaces they encapsulate. For each + /// such option it will retrieve options for these option spaces and append + /// as sub-options to options belonging to "foo". + /// + /// @param option_space Name of the option space containing option to + /// which encapsulated options are appended. + void encapsulateInternal(const std::string& option_space); + + /// @brief Appends encapsulated options from the option space encapsulated + /// by the specified option. + /// + /// This method will go over all options belonging to the encapsulated space + /// and will check which option spaces they encapsulate recursively, + /// adding these options to the current option + /// + /// @param option which encapsulated options. + void encapsulateInternal(const OptionPtr& option); + + /// @brief Merges data from two option containers. + /// + /// This method merges options from one option container to another + /// option container. This function is templated because containers + /// may use different type of selectors. For non-vendor options + /// the selector is of the @c std::string type, for vendor options + /// the selector is of the @c uint32_t type. + /// + /// @param src_container Reference to a container from which the data + /// will be merged. + /// @param [out] dest_container Reference to a container to which the + /// data will be merged. + /// @tparam Type of the selector: @c std::string or @c uint32_t. + template <typename Selector> + void mergeInternal(const OptionSpaceContainer<OptionContainer, + OptionDescriptor, Selector>& src_container, + OptionSpaceContainer<OptionContainer, + OptionDescriptor, Selector>& dest_container) const; + + /// @brief A flag indicating if options have been encapsulated. + bool encapsulated_; + + /// @brief Type of the container holding options grouped by option space. + typedef OptionSpaceContainer<OptionContainer, OptionDescriptor, + std::string> OptionSpaceCollection; + /// @brief Container holding options grouped by option space. + OptionSpaceCollection options_; + + /// @brief Type of the container holding options grouped by vendor id. + typedef OptionSpaceContainer<OptionContainer, OptionDescriptor, + uint32_t> VendorOptionSpaceCollection; + /// @brief Container holding options grouped by vendor id. + VendorOptionSpaceCollection vendor_options_; +}; + +/// @name Pointers to the @c CfgOption objects. +//@{ +/// @brief Non-const pointer. +typedef boost::shared_ptr<CfgOption> CfgOptionPtr; + +/// @brief Const pointer. +typedef boost::shared_ptr<const CfgOption> ConstCfgOptionPtr; + +/// @brief Const pointer list. +typedef std::list<ConstCfgOptionPtr> CfgOptionList; + +//@} + +} +} + +#endif // CFG_OPTION_H |