1 // Copyright (C) 2014-2021 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 
7 #ifndef CFG_OPTION_H
8 #define CFG_OPTION_H
9 
10 #include <dhcp/option.h>
11 #include <dhcp/option_space_container.h>
12 #include <cc/cfg_to_element.h>
13 #include <cc/stamped_element.h>
14 #include <cc/user_context.h>
15 #include <dhcpsrv/cfg_option_def.h>
16 #include <dhcpsrv/key_from_key.h>
17 #include <boost/multi_index_container.hpp>
18 #include <boost/multi_index/hashed_index.hpp>
19 #include <boost/multi_index/ordered_index.hpp>
20 #include <boost/multi_index/sequenced_index.hpp>
21 #include <boost/multi_index/mem_fun.hpp>
22 #include <boost/multi_index/member.hpp>
23 #include <boost/shared_ptr.hpp>
24 #include <stdint.h>
25 #include <string>
26 #include <list>
27 
28 namespace isc {
29 namespace dhcp {
30 
31 class OptionDescriptor;
32 
33 /// A pointer to option descriptor.
34 typedef boost::shared_ptr<OptionDescriptor> OptionDescriptorPtr;
35 
36 /// @brief Option descriptor.
37 ///
38 /// Option descriptor holds instance of an option and additional information
39 /// for this option. This information comprises whether this option is sent
40 /// to DHCP client only on request (persistent = false) or always
41 /// (persistent = true).
42 class OptionDescriptor : public data::StampedElement, public data::UserContext {
43 public:
44     /// @brief Option instance.
45     OptionPtr option_;
46 
47     /// @brief Persistence flag.
48     ///
49     /// If true, option is always sent to the client. If false, option is
50     /// sent to the client when requested using ORO or PRL option.
51     bool persistent_;
52 
53     /// @brief Option value in textual (CSV) format.
54     ///
55     /// This field is used to convey option value in human readable format,
56     /// the same as used to specify option value in the server configuration.
57     /// This value is optional and can be held in the host reservations
58     /// database instead of the binary format.
59     ///
60     /// Note that this value is carried in the option descriptor, rather than
61     /// @c Option instance because it is a server specific value (same as
62     /// persistence flag).
63     ///
64     /// An example of the formatted value is: "2001:db8:1::1, 23, some text"
65     /// for the option which carries IPv6 address, a number and a text.
66     std::string formatted_value_;
67 
68     /// @brief Option space name.
69     ///
70     /// Options are associated with option spaces. Typically, such association
71     /// is made when the option is stored in the @c OptionContainer. However,
72     /// in some cases it is also required to associate option with the particular
73     /// option space outside of the container. In particular, when the option
74     /// is fetched from a database. The database configuration backend will
75     /// set option space upon return of the option. In other cases this value
76     /// won't be set.
77     std::string space_name_;
78 
79     /// @brief Constructor.
80     ///
81     /// @param opt option instance.
82     /// @param persist if true, option is always sent.
83     /// @param formatted_value option value in the textual format (optional).
84     /// @param user_context user context (optional).
85     OptionDescriptor(const OptionPtr& opt, bool persist,
86                      const std::string& formatted_value = "",
87                      data::ConstElementPtr user_context = data::ConstElementPtr())
StampedElement()88         : data::StampedElement(), option_(opt), persistent_(persist),
89           formatted_value_(formatted_value),
90           space_name_() {
91         setContext(user_context);
92     };
93 
94     /// @brief Constructor.
95     ///
96     /// @param persist if true option is always sent.
OptionDescriptor(bool persist)97     OptionDescriptor(bool persist)
98         : data::StampedElement(), option_(OptionPtr()), persistent_(persist),
99           formatted_value_(), space_name_() {};
100 
101     /// @brief Copy constructor.
102     ///
103     /// @param desc option descriptor to be copied.
OptionDescriptor(const OptionDescriptor & desc)104     OptionDescriptor(const OptionDescriptor& desc)
105         : data::StampedElement(desc),
106           option_(desc.option_),
107           persistent_(desc.persistent_),
108           formatted_value_(desc.formatted_value_),
109           space_name_(desc.space_name_) {
110         setContext(desc.getContext());
111     };
112 
113     /// @brief Assignment operator.
114     ///
115     /// @param other option descriptor to be assigned from.
116     OptionDescriptor& operator=(const OptionDescriptor& other) {
117         if (this != &other) {
118             // Not self-assignment.
119             data::StampedElement::operator=(other);
120             option_ = other.option_;
121             persistent_ = other.persistent_;
122             formatted_value_ = other.formatted_value_;
123             space_name_ = other.space_name_;
124             setContext(other.getContext());
125         }
126         return (*this);
127     }
128 
129     /// @brief Factory function creating an instance of the @c OptionDescriptor.
130     ///
131     /// @param opt option instance.
132     /// @param persist if true, option is always sent.
133     /// @param formatted_value option value in the textual format (optional).
134     /// @param user_context user context (optional).
135     ///
136     /// @return Pointer to the @c OptionDescriptor instance.
137     static OptionDescriptorPtr create(const OptionPtr& opt,
138                                       bool persist,
139                                       const std::string& formatted_value = "",
140                                       data::ConstElementPtr user_context =
141                                       data::ConstElementPtr());
142 
143     /// @brief Factory function creating an instance of the @c OptionDescriptor.
144     ///
145     /// @param persist if true option is always sent.
146     ///
147     /// @return Pointer to the @c OptionDescriptor instance.
148     static OptionDescriptorPtr create(bool persist);
149 
150     /// @brief Factory function creating an instance of the @c OptionDescriptor.
151     ///
152     /// @param desc option descriptor to be copied.
153     ///
154     /// @return Pointer to the @c OptionDescriptor instance.
155     static OptionDescriptorPtr create(const OptionDescriptor& desc);
156 
157     /// @brief Checks if the one descriptor is equal to another.
158     ///
159     /// @param other Other option descriptor to compare to.
160     ///
161     /// @return true if descriptors equal, false otherwise.
162     bool equals(const OptionDescriptor& other) const;
163 
164     /// @brief Equality operator.
165     ///
166     /// @param other Other option descriptor to compare to.
167     ///
168     /// @return true if descriptors equal, false otherwise.
169     bool operator==(const OptionDescriptor& other) const {
170         return (equals(other));
171     }
172 
173     /// @brief Inequality operator.
174     ///
175     /// @param other Other option descriptor to compare to.
176     ///
177     /// @return true if descriptors unequal, false otherwise.
178     bool operator!=(const OptionDescriptor& other) const {
179         return (!equals(other));
180     }
181 };
182 
183 /// @brief Multi index container for DHCP option descriptors.
184 ///
185 /// This container comprises three indexes to access option
186 /// descriptors:
187 /// - sequenced index: used to access elements in the order they
188 /// have been added to the container,
189 /// - option type index: used to search option descriptors containing
190 /// options with specific option code (aka option type).
191 /// - persistency flag index: used to search option descriptors with
192 /// 'persistent' flag set to true.
193 ///
194 /// This container is the equivalent of three separate STL containers:
195 /// - std::list of all options,
196 /// - std::multimap of options with option code used as a multimap key,
197 /// - std::multimap of option descriptors with option persistency flag
198 /// used as a multimap key.
199 /// The major advantage of this container over 3 separate STL containers
200 /// is automatic synchronization of all indexes when elements are added,
201 /// removed or modified in the container. With separate containers,
202 /// the synchronization would have to be guaranteed by the Subnet class
203 /// code. This would increase code complexity and presumably it would
204 /// be much harder to add new search criteria (indexes).
205 ///
206 /// @todo we may want to search for options using option spaces when
207 /// they are implemented.
208 ///
209 /// @see http://www.boost.org/doc/libs/1_51_0/libs/multi_index/doc/index.html
210 typedef boost::multi_index_container<
211     // Container comprises elements of OptionDescriptor type.
212     OptionDescriptor,
213     // Here we start enumerating various indexes.
214     boost::multi_index::indexed_by<
215         // Sequenced index allows accessing elements in the same way
216         // as elements in std::list.
217         // Sequenced is an index #0.
218         boost::multi_index::sequenced<>,
219         // Start definition of index #1.
220         boost::multi_index::hashed_non_unique<
221             // KeyFromKeyExtractor is the index key extractor that allows
222             // accessing option type being held by the OptionPtr through
223             // OptionDescriptor structure.
224             KeyFromKeyExtractor<
225                 // Use option type as the index key. The type is held
226                 // in OptionPtr object so we have to call Option::getType
227                 // to retrieve this key for each element.
228                 boost::multi_index::const_mem_fun<
229                     Option,
230                     uint16_t,
231                     &Option::getType
232                 >,
233                 // Indicate that OptionPtr is a member of
234                 // OptionDescriptor structure.
235                 boost::multi_index::member<
236                     OptionDescriptor,
237                     OptionPtr,
238                     &OptionDescriptor::option_
239                  >
240             >
241         >,
242         // Start definition of index #2.
243         // Use 'persistent' struct member as a key.
244         boost::multi_index::hashed_non_unique<
245             boost::multi_index::member<
246                 OptionDescriptor,
247                 bool,
248                 &OptionDescriptor::persistent_
249             >
250         >,
251         // Start definition of index #3.
252         // Use BaseStampedElement::getModificationTime as a key.
253         boost::multi_index::ordered_non_unique<
254             boost::multi_index::const_mem_fun<
255                 data::BaseStampedElement,
256                 boost::posix_time::ptime,
257                 &data::BaseStampedElement::getModificationTime
258             >
259         >,
260 
261         // Start definition of index #4.
262         // Use BaseStampedElement::getId as a key.
263         boost::multi_index::hashed_non_unique<
264             boost::multi_index::tag<OptionIdIndexTag>,
265             boost::multi_index::const_mem_fun<data::BaseStampedElement, uint64_t,
266                                               &data::BaseStampedElement::getId>
267         >
268     >
269 > OptionContainer;
270 
271 /// Pointer to the OptionContainer object.
272 typedef boost::shared_ptr<OptionContainer> OptionContainerPtr;
273 /// Type of the index #1 - option type.
274 typedef OptionContainer::nth_index<1>::type OptionContainerTypeIndex;
275 /// Pair of iterators to represent the range of options having the
276 /// same option type value. The first element in this pair represents
277 /// the beginning of the range, the second element represents the end.
278 typedef std::pair<OptionContainerTypeIndex::const_iterator,
279                   OptionContainerTypeIndex::const_iterator> OptionContainerTypeRange;
280 /// Type of the index #2 - option persistency flag.
281 typedef OptionContainer::nth_index<2>::type OptionContainerPersistIndex;
282 /// Pair of iterators to represent the range of options having the
283 /// same persistency flag. The first element in this pair represents
284 /// the beginning of the range, the second element represents the end.
285 typedef std::pair<OptionContainerPersistIndex::const_iterator,
286                   OptionContainerPersistIndex::const_iterator> OptionContainerPersistRange;
287 
288 /// @brief Represents option data configuration for the DHCP server.
289 ///
290 /// This class holds a collection of options to be sent to a DHCP client.
291 /// Options are grouped by the option space or vendor identifier (for
292 /// vendor options).
293 ///
294 /// The server configuration allows for specifying two distinct collections
295 /// of options: global options and per-subnet options in which some options
296 /// may overlap.
297 ///
298 /// The collection of global options specify options being sent to the client
299 /// belonging to any subnets, i.e. global options are "inherited" by all
300 /// subnets.
301 ///
302 /// The per-subnet options are configured for a particular subnet and are sent
303 /// to clients which belong to this subnet. The values of the options specified
304 /// for a particular subnet override the values of the global options.
305 ///
306 /// This class represents a single collection of options (either global or
307 /// per-subnet). Each subnet holds its own object of the @c CfgOption type. The
308 /// @c CfgMgr holds a @c CfgOption object representing global options.
309 ///
310 /// Note that having a separate copy of the @c CfgOption to represent global
311 /// options is useful when the client requests stateless configuration from
312 /// the DHCP server and no subnet is selected for this client. This client
313 /// will only receive global options.
314 class CfgOption : public isc::data::CfgToElement {
315 public:
316 
317     /// @brief default constructor
318     CfgOption();
319 
320     /// @brief Indicates the object is empty
321     ///
322     /// @return true when the object is empty
323     bool empty() const;
324 
325     /// @name Methods and operators used for comparing objects.
326     ///
327     //@{
328     /// @brief Check if configuration is equal to other configuration.
329     ///
330     /// @param other An object holding configuration to compare to.
331     ///
332     /// @return true if configurations are equal, false otherwise.
333     bool equals(const CfgOption& other) const;
334 
335     /// @brief Equality operator.
336     ///
337     /// @param other An object holding configuration to compare to.
338     ///
339     /// @return true if configurations are equal, false otherwise.
340     bool operator==(const CfgOption& other) const {
341         return (equals(other));
342     }
343 
344     /// @brief Inequality operator.
345     ///
346     /// @param other An object holding configuration to compare to.
347     ///
348     /// @return true if configurations are unequal, false otherwise.
349     bool operator!=(const CfgOption& other) const {
350         return (!equals(other));
351     }
352 
353     //@}
354 
355     /// @brief Adds instance of the option to the configuration.
356     ///
357     /// There are two types of options which may be passed to this method:
358     /// - vendor options
359     /// - non-vendor options
360     ///
361     /// The non-vendor options are grouped by the name of the option space
362     /// (specified in textual format). The vendor options are grouped by the
363     /// vendor identifier, which is a 32-bit unsigned integer value.
364     ///
365     /// In order to add new vendor option to the list the option space name
366     /// (last argument of this method) should be specified as "vendor-X" where
367     /// "X" is a 32-bit unsigned integer, e.g. "vendor-1234". Options for which
368     /// the @c option_space argument doesn't follow this format are added as
369     /// non-vendor options.
370     ///
371     /// @param option Pointer to the option being added.
372     /// @param persistent Boolean value which specifies if the option should
373     /// be sent to the client regardless if requested (true), or nor (false)
374     /// @param option_space Option space name.
375     /// @param id Optional database id to be associated with the option.
376     ///
377     /// @throw isc::BadValue if the option space is invalid.
378     void add(const OptionPtr& option, const bool persistent,
379              const std::string& option_space,
380              const uint64_t id = 0);
381 
382     /// @brief A variant of the @ref CfgOption::add method which takes option
383     /// descriptor as an argument.
384     ///
385     /// @param desc Option descriptor holding option instance and other
386     /// parameters pertaining to the option.
387     /// @param option_space Option space name.
388     ///
389     /// @throw isc::BadValue if the option space is invalid.
390     void add(const OptionDescriptor& desc, const std::string& option_space);
391 
392     /// @brief Replaces the instance of an option within this collection
393     ///
394     /// This method locates the option within the given space and replaces
395     /// it with a copy of the given descriptor.  This effectively updates
396     /// the contents without altering the container indexing.
397     ///
398     /// @param desc Option descriptor holding option instance and other
399     /// parameters pertaining to the option.
400     /// @param option_space Option space name.
401     ///
402     /// @throw isc::BadValue if the descriptor's option instance is null,
403     /// if  space is invalid, or if the option does not already exist
404     /// in the given space.
405     void replace(const OptionDescriptor& desc, const std::string& option_space);
406 
407     /// @brief Merges another option configuration into this one.
408     ///
409     /// This method calls @c mergeTo() to add this configuration's
410     /// options into @c other (skipping any duplicates).  Next it calls
411     /// @c createDescriptorOption() for each option descriptor in the
412     /// merged set.  This (re)-creates each descriptor's option based on
413     /// the merged set of opt definitions. Finally, it calls
414     /// @c copyTo() to overwrite this configuration's options with
415     /// the merged set in @c other.
416     ///
417     /// @warning The merge operation will affect the @c other configuration.
418     /// Therefore, the caller must not rely on the data held in the @c other
419     /// object after the call to @c merge. Also, the data held in @c other must
420     /// not be modified after the call to @c merge because it may affect the
421     /// merged configuration.
422     ///
423     /// @param cfg_def set of of user-defined option definitions to use
424     /// when merging.
425     /// @param other option configuration to merge in.
426     void merge(CfgOptionDefPtr cfg_def, CfgOption& other);
427 
428     /// @brief Re-create the option in each descriptor based on given definitions
429     ///
430     /// Invokes @c createDescriptorOption() on each option descriptor in
431     /// each option space, passing in the given dictionary of option
432     /// definitions.  If the descriptor's option is re-created, then the
433     /// descriptor is updated by calling @c replace().
434     ///
435     /// @param cfg_def set of of user-defined option definitions to use
436     /// when creating option instances.
437     void createOptions(CfgOptionDefPtr cfg_def);
438 
439     /// @brief Creates an option descriptor's option based on a set of option defs
440     ///
441     /// This function's primary use is to create definition specific options for
442     /// option descriptors fetched from a configuration backend, as part of a
443     /// configuration merge.
444     ///
445     /// Given an OptionDescriptor whose option_ member contains a generic option
446     /// (i.e has a code and/or data), this function will attempt to find a matching
447     /// definition and then use that definition's factory to create an option
448     /// instance specific to that definition.   It will then replace the descriptor's
449     /// generic option with the specific option.
450     ///
451     /// Three sources of definitions are searched, in the following order:
452     ///
453     /// 1. Standard option definitions (@c LIBDHCP::getOptionDef))
454     /// 2. Vendor option definitions (@c LIBDHCP::getVendorOptionDef))
455     /// 3. User specified definitions passed in via cfg_def parameter.
456     ///
457     /// The code will use the first matching definition found.  It then applies
458     /// the following rules:
459     ///
460     /// -# If no definition is found but the descriptor conveys a non-empty
461     /// formatted value, throw an error.
462     /// -# If not definition is found and there is no formatted value, return
463     /// This leaves intact the generic option in the descriptor.
464     /// -# If a definition is found and there is no formatted value, pass the
465     /// descriptor's generic option's data into the definition's factory. Replace
466     /// the descriptor's option with the newly created option.
467     /// -# If a definition is found and there is a formatted value, split
468     /// the value into vector of values and pass that into the definition's
469     /// factory. Replace the descriptor's option with the newly created option.
470     ///
471     /// @param cfg_def the user specified definitions to use
472     /// @param space the option space name of the option
473     /// @param opt_desc OptionDescriptor describing the option.
474     ///
475     /// @return True if the descriptor's option instance was replaced.
476     /// @throw InvalidOperation if the descriptor conveys a formatted value and
477     /// there is no definition matching the option code in the given space, or
478     /// if the definition factory invocation fails.
479     static bool createDescriptorOption(CfgOptionDefPtr cfg_def, const std::string& space,
480                              OptionDescriptor& opt_desc);
481 
482     /// @brief Merges this configuration to another configuration.
483     ///
484     /// This method iterates over the configuration items held in this
485     /// configuration and copies them to the configuration specified
486     /// as a parameter. If an item exists in the destination it is not
487     /// copied.
488     ///
489     /// @param [out] other Configuration object to merge to.
490     void mergeTo(CfgOption& other) const;
491 
492     /// @brief Copies this configuration to another configuration.
493     ///
494     /// This method copies options configuration to another object.
495     ///
496     /// @param [out] other An object to copy the configuration to.
497     void copyTo(CfgOption& other) const;
498 
499     /// @brief Appends encapsulated options to top-level options.
500     ///
501     /// This method iterates over the top-level options (from "dhcp4"
502     /// and "dhcp6" option space) and checks which option spaces these
503     /// options encapsulate. For each encapsulated option space, the
504     /// options from this option space are appended to top-level options.
505     void encapsulate();
506 
507     /// @brief Returns all options for the specified option space.
508     ///
509     /// This method will not return vendor options, i.e. having option space
510     /// name in the format of "vendor-X" where X is 32-bit unsigned integer.
511     /// See @c getAll(uint32_t) for vendor options.
512     ///
513     /// @param option_space Name of the option space.
514     ///
515     /// @return Pointer to the container holding returned options. This
516     /// container is empty if no options have been found.
517     OptionContainerPtr getAll(const std::string& option_space) const;
518 
519     /// @brief Returns vendor options for the specified vendor id.
520     ///
521     /// @param vendor_id Vendor id for which options are to be returned.
522     ///
523     /// @return Pointer to the container holding returned options. This
524     /// container is empty if no options have been found.
525     OptionContainerPtr getAll(const uint32_t vendor_id) const;
526 
527     /// @brief Returns option for the specified key and option code.
528     ///
529     /// The key should be a string, in which case it specifies an option space
530     /// name, or an uint32_t value, in which case it specifies a vendor
531     /// identifier.
532     ///
533     /// @note If there are multiple options with the same key, only one will
534     /// be returned.  No indication will be given of the presence of others,
535     /// and the instance returned is not determinable.
536     ///
537     /// @param key Option space name or vendor identifier.
538     /// @param option_code Code of the option to be returned.
539     /// @tparam Selector one of: @c std::string or @c uint32_t
540     ///
541     /// @return Descriptor of the option. If option hasn't been found, the
542     /// descriptor holds NULL option.
543     template<typename Selector>
get(const Selector & key,const uint16_t option_code)544     OptionDescriptor get(const Selector& key,
545                          const uint16_t option_code) const {
546 
547         // Check for presence of options.
548         OptionContainerPtr options = getAll(key);
549         if (!options || options->empty()) {
550             return (OptionDescriptor(false));
551         }
552 
553         // Some options present, locate the one we are interested in.
554         const OptionContainerTypeIndex& idx = options->get<1>();
555         OptionContainerTypeIndex::const_iterator od_itr = idx.find(option_code);
556         if (od_itr == idx.end()) {
557             return (OptionDescriptor(false));
558         }
559 
560         return (*od_itr);
561     }
562 
563     /// @brief Deletes option for the specified option space and option code.
564     ///
565     /// If the option is encapsulated within some non top level option space,
566     /// it is also deleted from all option instances encapsulating this
567     /// option space.
568     ///
569     /// @param option_space Option space name.
570     /// @param option_code Code of the option to be returned.
571     ///
572     /// @return Number of deleted options.
573     size_t del(const std::string& option_space, const uint16_t option_code);
574 
575     /// @brief Deletes vendor option for the specified vendor id.
576     ///
577     /// @param vendor_id Vendor identifier.
578     /// @param option_code Option code.
579     ///
580     /// @return Number of deleted options.
581     size_t del(const uint32_t vendor_id, const uint16_t option_code);
582 
583     /// @brief Deletes all options having a given database id.
584     ///
585     /// Note that there are cases when there will be multiple options
586     /// having the same id (typically id of 0). When configuration backend
587     /// is in use it sets the unique ids from the database. In cases when
588     /// the configuration backend is not used, the ids default to 0.
589     /// Passing the id of 0 would result in deleting all options that were
590     /// not added via the database.
591     ///
592     /// Both regular and vendor specific options are deleted with this
593     /// method.
594     ///
595     /// This method internally calls @c encapsulate() after deleting
596     /// options having the given id.
597     ///
598     /// @param id Identifier of the options to be deleted.
599     ///
600     /// @return Number of deleted options. Note that if a single option
601     /// instance is encapsulated by multiple options it adds 1 to the
602     /// number of deleted options even though the same instance is
603     /// deleted from multiple higher level options.
604     size_t del(const uint64_t id);
605 
606     /// @brief Returns a list of configured option space names.
607     ///
608     /// The returned option space names exclude vendor option spaces,
609     /// such as "vendor-1234". These are returned by the
610     /// @ref getVendorIdsSpaceNames.
611     ///
612     /// @return List comprising option space names.
getOptionSpaceNames()613     std::list<std::string> getOptionSpaceNames() const {
614         return (options_.getOptionSpaceNames());
615     }
616 
617     /// @brief Returns a list of all configured  vendor identifiers.
getVendorIds()618     std::list<uint32_t> getVendorIds() const {
619         return (vendor_options_.getOptionSpaceNames());
620     }
621 
622     /// @brief Returns a list of option space names for configured vendor ids.
623     ///
624     /// For each vendor-id the option space name returned is constructed
625     /// as "vendor-XYZ" where XYZ is a @c uint32_t value without leading
626     /// zeros.
627     ///
628     /// @return List comprising option space names for vendor options.
629     std::list<std::string> getVendorIdsSpaceNames() const;
630 
631     /// @brief Unparse a configuration object
632     ///
633     /// @return a pointer to unparsed configuration
634     virtual isc::data::ElementPtr toElement() const;
635 
636     /// @brief Unparse a configuration object with optionally including
637     /// the metadata.
638     ///
639     /// @param include_metadata boolean value indicating if the metadata
640     /// should be included (if true) or not (if false).
641     ///
642     /// @return A pointer to the unparsed configuration.
643     isc::data::ElementPtr
644     toElementWithMetadata(const bool include_metadata) const;
645 
646 private:
647 
648     /// @brief Appends encapsulated options to the options in an option space.
649     ///
650     /// This method appends sub-options to the options belonging to the
651     /// particular option space. For example: if the option space "foo"
652     /// is specified, this function will go over all options belonging to
653     /// "foo" and will check which option spaces they encapsulate. For each
654     /// such option it will retrieve options for these option spaces and append
655     /// as sub-options to options belonging to "foo".
656     ///
657     /// @param option_space Name of the option space containing option to
658     /// which encapsulated options are appended.
659     void encapsulateInternal(const std::string& option_space);
660 
661     /// @brief Appends encapsulated options from the option space encapsulated
662     /// by the specified option.
663     ///
664     /// This method will go over all options belonging to the encapsulated space
665     /// and will check which option spaces they encapsulate recursively,
666     /// adding these options to the current option
667     ///
668     /// @param option which encapsulated options.
669     void encapsulateInternal(const OptionPtr& option);
670 
671     /// @brief Merges data from two option containers.
672     ///
673     /// This method merges options from one option container to another
674     /// option container. This function is templated because containers
675     /// may use different type of selectors. For non-vendor options
676     /// the selector is of the @c std::string type, for vendor options
677     /// the selector is of the @c uint32_t type.
678     ///
679     /// @param src_container Reference to a container from which the data
680     /// will be merged.
681     /// @param [out] dest_container Reference to a container to which the
682     /// data will be merged.
683     /// @tparam Type of the selector: @c std::string or @c uint32_t.
684     template <typename Selector>
685     void mergeInternal(const OptionSpaceContainer<OptionContainer,
686                        OptionDescriptor, Selector>& src_container,
687                        OptionSpaceContainer<OptionContainer,
688                        OptionDescriptor, Selector>& dest_container) const;
689 
690     /// @brief Type of the container holding options grouped by option space.
691     typedef OptionSpaceContainer<OptionContainer, OptionDescriptor,
692                                  std::string> OptionSpaceCollection;
693     /// @brief Container holding options grouped by option space.
694     OptionSpaceCollection options_;
695 
696     /// @brief Type of the container holding options grouped by vendor id.
697     typedef OptionSpaceContainer<OptionContainer, OptionDescriptor,
698                                  uint32_t> VendorOptionSpaceCollection;
699     /// @brief Container holding options grouped by vendor id.
700     VendorOptionSpaceCollection vendor_options_;
701 };
702 
703 /// @name Pointers to the @c CfgOption objects.
704 //@{
705 /// @brief Non-const pointer.
706 typedef boost::shared_ptr<CfgOption> CfgOptionPtr;
707 
708 /// @brief Const pointer.
709 typedef boost::shared_ptr<const CfgOption> ConstCfgOptionPtr;
710 
711 /// @brief Const pointer list.
712 typedef std::list<ConstCfgOptionPtr> CfgOptionList;
713 
714 //@}
715 
716 }
717 }
718 
719 #endif // CFG_OPTION_H
720