diff options
Diffstat (limited to 'src/lib/dhcp/packet_queue_mgr.h')
-rw-r--r-- | src/lib/dhcp/packet_queue_mgr.h | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/src/lib/dhcp/packet_queue_mgr.h b/src/lib/dhcp/packet_queue_mgr.h new file mode 100644 index 0000000..4bb009a --- /dev/null +++ b/src/lib/dhcp/packet_queue_mgr.h @@ -0,0 +1,189 @@ +// Copyright (C) 2018-2021 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 PACKET_QUEUE_MGR_H +#define PACKET_QUEUE_MGR_H + +#include <cc/data.h> +#include <cc/simple_parser.h> +#include <dhcp/packet_queue.h> +#include <exceptions/exceptions.h> +#include <boost/shared_ptr.hpp> +#include <functional> +#include <map> +#include <string> + +namespace isc { +namespace dhcp { + +/// @brief Invalid Queue type exception +/// +/// Thrown when a packet queue manager doesn't recognize the type of the queue. +class InvalidQueueType : public Exception { +public: + InvalidQueueType(const char* file, size_t line, const char* what) : + isc::Exception(file, line, what) {} +}; + +/// @brief Packet Queue Managers (PQM). +/// +/// Base class to manage the registry of packet queue implementations +/// and the creation of and access to the current packet queue. +/// +/// @tparam PacktQueueTypePtr Base type of packet queues managed by +/// the manager (e.g. PacketQueue4Ptr, PacketQueue6Ptr). +template<typename PacketQueueTypePtr> +class PacketQueueMgr { +public: + /// @brief Defines the type of the packet queue factory function. + /// + /// Factory function returns a pointer to the instance of the packet + /// queue created. + typedef std::function<PacketQueueTypePtr(data::ConstElementPtr)> Factory; + + /// @brief Constructor. + PacketQueueMgr() + : factories_(), packet_queue_() { + } + + /// @brief Registers new queue factory function for a given queue type. + /// + /// The typical usage of this function is to make the PQM aware of a + /// packet queue implementation. This implementation may exist + /// in a hooks library. In such a case, this function should be called from + /// the @c load function in this library. When the queue impl is registered, + /// the server will use it when required by the configuration, i.e. a + /// user specifies it in "queue-control:queue-type" + /// + /// If the given queue type has already been registered, perhaps + /// by another hooks library, the PQM will refuse to register another + /// of the same type. + /// + /// @param queue_type Queue type, e.g. "kea-ring4" + /// @param factory Pointer to the queue factory function. + /// + /// @return true if the queue type has been successfully registered, false + /// if the type already exists. + bool registerPacketQueueFactory(const std::string& queue_type, + Factory factory) { + // Check if this backend has been already registered. + if (factories_.count(queue_type)) { + return (false); + } + + // Register the new backend. + factories_.insert(std::make_pair(queue_type, factory)); + return (true); + } + + /// @brief Unregisters the queue factory function for a given type. + /// + /// This function is used to remove the factory function for a given type. + /// Typically, it would be called when unloading the hook library which + /// loaded the type, and thus called by the library's @c unload function. + /// In addition to removing the factory, it will also destroy the current + /// queue if it is of the same queue-type as the factory being removed. + /// This avoids the nastiness that occurs when objecs are left in existence + /// after their library is unloaded. + /// + /// @param queue_type queue type, e.g. "kea-ring4". + /// + /// @return false if no factory for the given type was unregistered, true + /// if the factory was removed. + bool unregisterPacketQueueFactory(const std::string& queue_type) { + // Look for it. + auto index = factories_.find(queue_type); + + // Not there so nothing to do. + if (index == factories_.end()) { + return (false); + } + + // If the queue is of the type being unregistered, then remove it. We don't + // a queue instance outliving its library. + if ((packet_queue_) && (packet_queue_->getQueueType() == queue_type)) { + packet_queue_.reset(); + } + + // Remove the factory. + factories_.erase(index); + + return (true); + } + + /// @brief Create an instance of a packet queue. + /// + /// Replace the current packet queue with a new one based on the + /// given configuration parameters. The set of parameters must + /// contain at least "queue-type". This value is used to locate + /// the registered queue factory to invoke to create the new queue. + /// + /// The factory is passed the parameters verbatim for its use in + /// creating the new queue. Factories are expected to throw exceptions + /// on creation failure. Note the existing queue is not altered or + /// replaced unless the new queue is successfully created. + /// + /// @throw InvalidQueueParameter if parameters is not map that contains + /// "queue-type", InvalidQueueType if the queue type requested is not + /// supported. + /// @throw Unexpected if the backend factory function returned NULL. + void createPacketQueue(data::ConstElementPtr parameters) { + if (!parameters) { + isc_throw(Unexpected, "createPacketQueue - queue parameters is null"); + } + + // Get the database type to locate a factory function. + std::string queue_type ; + try { + queue_type = data::SimpleParser::getString(parameters, "queue-type"); + } catch (const std::exception& ex) { + isc_throw(InvalidQueueParameter, "queue-type missing or invalid: " << ex.what()); + } + + // Look up the factory. + auto index = factories_.find(queue_type); + + // Punt if there is no matching factory. + if (index == factories_.end()) { + isc_throw(InvalidQueueType, "The type of the packet queue: '" << + queue_type << "' is not supported"); } + + // Call the factory to create the new queue. + // Factories should throw InvalidQueueParameter if given + // bad values in the control. + auto new_queue = index->second(parameters); + if (!new_queue) { + isc_throw(Unexpected, "Packet queue " << queue_type << + " factory returned NULL"); + } + + // Replace the existing queue with the new one. + packet_queue_ = new_queue; + } + + /// @brief Returns underlying packet queue. + PacketQueueTypePtr getPacketQueue() const { + return (packet_queue_); + } + + /// @brief Destroys the current packet queue. + /// Any queued packets will be discarded. + void destroyPacketQueue() { + packet_queue_.reset(); + } + +protected: + /// @brief A map holding registered backend factory functions. + std::map<std::string, Factory> factories_; + + /// @brief the current queue_ ? + PacketQueueTypePtr packet_queue_; +}; + +} // end of namespace isc::dhcp +} // end of namespace isc + +#endif // PACKET_QUEUE_MGR_H |