diff options
Diffstat (limited to 'src/lib/dhcp/option_space_container.h')
-rw-r--r-- | src/lib/dhcp/option_space_container.h | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/src/lib/dhcp/option_space_container.h b/src/lib/dhcp/option_space_container.h new file mode 100644 index 0000000..d1c2952 --- /dev/null +++ b/src/lib/dhcp/option_space_container.h @@ -0,0 +1,184 @@ +// Copyright (C) 2013-2019 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 OPTION_SPACE_CONTAINER_H +#define OPTION_SPACE_CONTAINER_H + +#include <exceptions/exceptions.h> +#include <list> +#include <string> + +namespace isc { +namespace dhcp { + +/// @brief A tag for accessing DHCP options and definitions by id. +struct OptionIdIndexTag { }; + +/// @brief Simple container for option spaces holding various items. +/// +/// This helper class is used to store items of various types +/// that are grouped by option space names. Each option space is +/// mapped to a container that holds items which specifically can +/// be OptionDefinition objects or Subnet::OptionDescriptor structures. +/// +/// @tparam ContainerType of the container holding items within +/// option space. +/// @tparam ItemType type of the item being held by the container. +/// @tparam Selector a string (for option spaces) or uint32_t (for vendor options) +template<typename ContainerType, typename ItemType, typename Selector> +class OptionSpaceContainer { +public: + + /// Pointer to the container. + typedef boost::shared_ptr<ContainerType> ItemsContainerPtr; + + /// @brief Indicates the container is empty + /// + /// @return true when the container is empty + bool empty() const { + return (option_space_map_.empty()); + } + + /// @brief Adds a new item to the option_space. + /// + /// @param item reference to the item being added. + /// @param option_space name or vendor-id of the option space + void addItem(const ItemType& item, const Selector& option_space) { + ItemsContainerPtr items = getItems(option_space); + // Assume that the push_back() can't fail even when the + // ContainerType is a multi index container, i.e., assume + // there is no unique index which can raise a conflict. + static_cast<void>(items->push_back(item)); + option_space_map_[option_space] = items; + } + + /// @brief Get all items for the particular option space. + /// + /// @warning when there are no items for the specified option + /// space an empty container is created and returned. However + /// this container is not added to the list of option spaces. + /// + /// @param option_space name or vendor-id of the option space. + /// + /// @return pointer to the container holding items. + ItemsContainerPtr getItems(const Selector& option_space) const { + const typename OptionSpaceMap::const_iterator& items = + option_space_map_.find(option_space); + if (items == option_space_map_.end()) { + return (ItemsContainerPtr(new ContainerType())); + } + return (items->second); + } + + /// @brief Get a list of existing option spaces. + /// + /// @return a list of option spaces. + /// + /// @todo This function is likely to be removed once + /// we create a structure of OptionSpaces defined + /// through the configuration manager. + std::list<Selector> getOptionSpaceNames() const { + std::list<Selector> names; + for (typename OptionSpaceMap::const_iterator space = + option_space_map_.begin(); + space != option_space_map_.end(); ++space) { + names.push_back(space->first); + } + return (names); + } + + /// @brief Remove all items from the container. + void clearItems() { + option_space_map_.clear(); + } + + /// @brief Remove all options or option definitions with a given + /// database identifier. + /// + /// Note that there are cases when there will be multiple options + /// or option definitions 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 or option definitions that were + /// not added via the database. + /// + /// @param id Identifier of the items to be deleted. + /// + /// @return Number of deleted options or option definitions. + uint64_t deleteItems(const uint64_t id) { + uint64_t num_deleted = 0; + for (auto space : option_space_map_) { + auto container = space.second; + auto& index = container->template get<OptionIdIndexTag>(); + num_deleted += index.erase(id); + } + + return (num_deleted); + } + + /// @brief Check if two containers are equal. + /// + /// This method checks if option space container contains exactly + /// the same selectors and that there are exactly the same items + /// added for each selector. The order of items doesn't matter. + /// + /// @param other Other container to compare to. + /// + /// @return true if containers are equal, false otherwise. + bool equals(const OptionSpaceContainer& other) const { + for (typename OptionSpaceMap::const_iterator it = + option_space_map_.begin(); it != option_space_map_.end(); + ++it) { + + typename OptionSpaceMap::const_iterator other_it = + other.option_space_map_.find(it->first); + if (other_it == other.option_space_map_.end()) { + return (false); + } + + // If containers have different sizes it is an indication that + // they are unequal. + if (it->second->size() != other_it->second->size()) { + return (false); + } + + // If they have the same sizes, we have to compare each element. + for (typename ContainerType::const_iterator items_it = + it->second->begin(); + items_it != it->second->end(); ++items_it) { + + bool match_found = false; + for (typename ContainerType::const_iterator other_items_it = + other_it->second->begin(); + other_items_it != other_it->second->end(); + ++other_items_it) { + if (items_it->equals(*other_items_it)) { + match_found = true; + break; + } + } + + if (!match_found) { + return (false); + } + } + } + return (true); + } + +private: + + /// A map holding container (option space name or vendor-id is the key). + typedef std::map<Selector, ItemsContainerPtr> OptionSpaceMap; + OptionSpaceMap option_space_map_; +}; + + +} // end of isc::dhcp namespace +} // end of isc namespace + +#endif // OPTION_SPACE_CONTAINER_H |