lib_LTLIBRARIES = libkea-cfgclient.la
libkea_cfgclient_la_SOURCES = config_data.h config_data.cc
libkea_cfgclient_la_SOURCES += module_spec.h module_spec.cc
+libkea_cfgclient_la_SOURCES += base_command_mgr.cc base_command_mgr.h
libkea_cfgclient_la_SOURCES += command_mgr.cc command_mgr.h
libkea_cfgclient_la_SOURCES += command_socket.cc command_socket.h
libkea_cfgclient_la_SOURCES += command_socket_factory.cc command_socket_factory.h
--- /dev/null
+// Copyright (C) 2017 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/.
+
+#include <cc/command_interpreter.h>
+#include <config/base_command_mgr.h>
+#include <config/config_log.h>
+#include <boost/bind.hpp>
+
+using namespace isc::data;
+
+namespace isc {
+namespace config {
+
+BaseCommandMgr::BaseCommandMgr() {
+ registerCommand("list-commands", boost::bind(&BaseCommandMgr::listCommandsHandler,
+ this, _1, _2));
+}
+
+void
+BaseCommandMgr::registerCommand(const std::string& cmd, CommandHandler handler) {
+ if (!handler) {
+ isc_throw(InvalidCommandHandler, "Specified command handler is NULL");
+ }
+
+ HandlerContainer::const_iterator it = handlers_.find(cmd);
+ if (it != handlers_.end()) {
+ isc_throw(InvalidCommandName, "Handler for command '" << cmd
+ << "' is already installed.");
+ }
+
+ handlers_.insert(make_pair(cmd, handler));
+
+ LOG_DEBUG(command_logger, DBG_COMMAND, COMMAND_REGISTERED).arg(cmd);
+}
+
+void
+BaseCommandMgr::deregisterCommand(const std::string& cmd) {
+ if (cmd == "list-commands") {
+ isc_throw(InvalidCommandName,
+ "Can't uninstall internal command 'list-commands'");
+ }
+
+ HandlerContainer::iterator it = handlers_.find(cmd);
+ if (it == handlers_.end()) {
+ isc_throw(InvalidCommandName, "Handler for command '" << cmd
+ << "' not found.");
+ }
+ handlers_.erase(it);
+
+ LOG_DEBUG(command_logger, DBG_COMMAND, COMMAND_DEREGISTERED).arg(cmd);
+}
+
+void
+BaseCommandMgr::deregisterAll() {
+
+ // No need to log anything here. deregisterAll is not used in production
+ // code, just in tests.
+ handlers_.clear();
+ registerCommand("list-commands",
+ boost::bind(&BaseCommandMgr::listCommandsHandler, this, _1, _2));
+}
+
+isc::data::ConstElementPtr
+BaseCommandMgr::processCommand(const isc::data::ConstElementPtr& cmd) {
+ if (!cmd) {
+ return (createAnswer(CONTROL_RESULT_ERROR,
+ "Command processing failed: NULL command parameter"));
+ }
+
+ try {
+ ConstElementPtr arg;
+ std::string name = parseCommand(arg, cmd);
+
+ LOG_INFO(command_logger, COMMAND_RECEIVED).arg(name);
+
+ HandlerContainer::const_iterator it = handlers_.find(name);
+ if (it == handlers_.end()) {
+ // Ok, there's no such command.
+ return (createAnswer(CONTROL_RESULT_ERROR,
+ "'" + name + "' command not supported."));
+ }
+
+ // Call the actual handler and return whatever it returned
+ return (it->second(name, arg));
+
+ } catch (const Exception& e) {
+ LOG_WARN(command_logger, COMMAND_PROCESS_ERROR2).arg(e.what());
+ return (createAnswer(CONTROL_RESULT_ERROR,
+ std::string("Error during command processing:")
+ + e.what()));
+ }
+}
+
+isc::data::ConstElementPtr
+BaseCommandMgr::listCommandsHandler(const std::string& name,
+ const isc::data::ConstElementPtr& params) {
+ using namespace isc::data;
+ ElementPtr commands = Element::createList();
+ for (HandlerContainer::const_iterator it = handlers_.begin();
+ it != handlers_.end(); ++it) {
+ commands->add(Element::create(it->first));
+ }
+ return (createAnswer(CONTROL_RESULT_SUCCESS, commands));
+}
+
+
+} // namespace isc::config
+} // namespace isc
--- /dev/null
+// Copyright (C) 2017 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 BASE_COMMAND_MGR_H
+#define BASE_COMMAND_MGR_H
+
+#include <cc/data.h>
+#include <exceptions/exceptions.h>
+#include <boost/function.hpp>
+#include <map>
+#include <string>
+
+namespace isc {
+namespace config {
+
+/// @brief Exception indicating that the handler specified is not valid
+class InvalidCommandHandler : public Exception {
+public:
+ InvalidCommandHandler(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) { };
+};
+
+/// @brief Exception indicating that the command name is not valid
+class InvalidCommandName : public Exception {
+public:
+ InvalidCommandName(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) { };
+};
+
+/// @brief Commands Manager, responsible for processing external commands.
+///
+/// Commands Manager is a generic interface for handling external commands.
+/// Commands are received over control sockets. Derivations of this class
+/// provide implementations of the control socket layers, e.g. unix domain
+/// sockets, TCP sockets etc. This base class merely provides methods to manage
+/// command handling functions, i.e. register commands, deregister commands.
+/// It also includes a @ref BaseCommandMgr::processCommand method which
+/// uses the command as an input and invokes appropriate handlers.
+///
+/// The commands and responses are formatted using JSON.
+/// See http://kea.isc.org/wiki/StatsDesign for details.
+///
+/// Below is an example of the command using JSON format:
+/// @code
+/// {
+/// "command": "statistic-get",
+/// "arguments": {
+/// "name": "received-packets"
+/// }
+/// }
+/// @endcode
+///
+/// And the response is:
+///
+/// @code
+/// {
+/// "result": 0,
+/// "observations": {
+/// "received-packets": [ [ 1234, "2015-04-15 12:34:45.123" ] ]
+/// }
+/// }
+/// @endcode
+///
+/// BaseCommandsMgr does not implement the commands (except one,
+/// "list-commands") itself, but rather provides an interface
+/// (see @ref registerCommand, @ref deregisterCommand, @ref processCommand)
+/// for other components to use it.
+class BaseCommandMgr {
+public:
+
+ /// @brief Defines command handler type
+ ///
+ /// Command handlers are expected to use this format.
+ ///
+ /// @param name name of the commands
+ /// @param params parameters specific to the command
+ /// @return response (created with createAnswer())
+ typedef boost::function<isc::data::ConstElementPtr (const std::string& name,
+ const isc::data::ConstElementPtr& params)> CommandHandler;
+
+ /// @brief Constructor.
+ ///
+ /// Registers "list-commands" command.
+ BaseCommandMgr();
+
+ /// @brief Destructor.
+ virtual ~BaseCommandMgr() { };
+
+ /// @brief Triggers command processing.
+ ///
+ /// This method processes specified command. The command is specified using
+ /// a single Element. See @ref BaseCommandMgr for description of its syntax.
+ ///
+ /// @param cmd Pointer to the data element representing command in JSON
+ /// format.
+ virtual isc::data::ConstElementPtr
+ processCommand(const isc::data::ConstElementPtr& cmd);
+
+ /// @brief Registers specified command handler for a given command
+ ///
+ /// @param cmd Name of the command to be handled.
+ /// @param handler Pointer to the method that will handle the command.
+ void registerCommand(const std::string& cmd, CommandHandler handler);
+
+ /// @brief Deregisters specified command handler.
+ ///
+ /// @param cmd Name of the command that's no longer handled.
+ void deregisterCommand(const std::string& cmd);
+
+ /// @brief Auxiliary method that removes all installed commands.
+ ///
+ /// The only unwipeable method is list-commands, which is internally
+ /// handled at all times.
+ void deregisterAll();
+
+protected:
+
+ /// @brief Type of the container for command handlers.
+ typedef std::map<std::string, CommandHandler> HandlerContainer;
+
+ /// @brief Container for command handlers.
+ HandlerContainer handlers_;
+
+private:
+
+ /// @brief 'list-commands' command handler.
+ ///
+ /// This method implements command 'list-commands'. It returns a list of all
+ /// currently supported commands.
+ ///
+ /// @param name Name of the command (should always be 'list-commands').
+ /// @param params Additional parameters (ignored).
+ ///
+ /// @return Pointer to the structure that includes all currently supported
+ /// commands.
+ isc::data::ConstElementPtr
+ listCommandsHandler(const std::string& name,
+ const isc::data::ConstElementPtr& params);
+};
+
+} // end of namespace isc::config
+} // end of namespace isc
+
+#endif
-// Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015-2017 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
namespace isc {
namespace config {
-CommandMgr::CommandMgr() {
- registerCommand("list-commands",
- boost::bind(&CommandMgr::listCommandsHandler, this, _1, _2));
+CommandMgr::CommandMgr()
+ : BaseCommandMgr() {
}
CommandSocketPtr
return (cmd_mgr);
}
-void CommandMgr::registerCommand(const std::string& cmd, CommandHandler handler) {
-
- if (!handler) {
- isc_throw(InvalidCommandHandler, "Specified command handler is NULL");
- }
-
- HandlerContainer::const_iterator it = handlers_.find(cmd);
- if (it != handlers_.end()) {
- isc_throw(InvalidCommandName, "Handler for command '" << cmd
- << "' is already installed.");
- }
-
- handlers_.insert(make_pair(cmd, handler));
-
- LOG_DEBUG(command_logger, DBG_COMMAND, COMMAND_REGISTERED).arg(cmd);
-}
-
-void CommandMgr::deregisterCommand(const std::string& cmd) {
- if (cmd == "list-commands") {
- isc_throw(InvalidCommandName,
- "Can't uninstall internal command 'list-commands'");
- }
-
- HandlerContainer::iterator it = handlers_.find(cmd);
- if (it == handlers_.end()) {
- isc_throw(InvalidCommandName, "Handler for command '" << cmd
- << "' not found.");
- }
- handlers_.erase(it);
-
- LOG_DEBUG(command_logger, DBG_COMMAND, COMMAND_DEREGISTERED).arg(cmd);
-}
-
-void CommandMgr::deregisterAll() {
-
- // No need to log anything here. deregisterAll is not used in production
- // code, just in tests.
- handlers_.clear();
- registerCommand("list-commands",
- boost::bind(&CommandMgr::listCommandsHandler, this, _1, _2));
-}
-
void
CommandMgr::commandReader(int sockfd) {
}
}
-isc::data::ConstElementPtr
-CommandMgr::processCommand(const isc::data::ConstElementPtr& cmd) {
- if (!cmd) {
- return (createAnswer(CONTROL_RESULT_ERROR,
- "Command processing failed: NULL command parameter"));
- }
-
- try {
- ConstElementPtr arg;
- std::string name = parseCommand(arg, cmd);
-
- LOG_INFO(command_logger, COMMAND_RECEIVED).arg(name);
-
- HandlerContainer::const_iterator it = handlers_.find(name);
- if (it == handlers_.end()) {
- // Ok, there's no such command.
- return (createAnswer(CONTROL_RESULT_ERROR,
- "'" + name + "' command not supported."));
- }
-
- // Call the actual handler and return whatever it returned
- return (it->second(name, arg));
-
- } catch (const Exception& e) {
- LOG_WARN(command_logger, COMMAND_PROCESS_ERROR2).arg(e.what());
- return (createAnswer(CONTROL_RESULT_ERROR,
- std::string("Error during command processing:")
- + e.what()));
- }
-}
-
-isc::data::ConstElementPtr
-CommandMgr::listCommandsHandler(const std::string& name,
- const isc::data::ConstElementPtr& params) {
- using namespace isc::data;
- ElementPtr commands = Element::createList();
- for (HandlerContainer::const_iterator it = handlers_.begin();
- it != handlers_.end(); ++it) {
- commands->add(Element::create(it->first));
- }
- return (createAnswer(CONTROL_RESULT_SUCCESS, commands));
-}
-
}; // end of isc::config
}; // end of isc
-// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015-2017 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
#define COMMAND_MGR_H
#include <cc/data.h>
+#include <config/base_command_mgr.h>
#include <config/command_socket.h>
#include <boost/noncopyable.hpp>
-#include <boost/function.hpp>
-#include <string>
#include <list>
-#include <map>
namespace isc {
namespace config {
-/// @brief CommandMgr exception indicating that the handler specified is not valid
-class InvalidCommandHandler : public Exception {
-public:
- InvalidCommandHandler(const char* file, size_t line, const char* what) :
- isc::Exception(file, line, what) { };
-};
-
-/// @brief CommandMgr exception indicating that the command name is not valid
-class InvalidCommandName : public Exception {
-public:
- InvalidCommandName(const char* file, size_t line, const char* what) :
- isc::Exception(file, line, what) { };
-};
-
-/// @brief Commands Manager, responsible for processing external commands
+/// @brief Commands Manager implementation for the Kea servers.
///
-/// Commands Manager is a generic interface for handling external commands.
-/// Commands can be received over control sockets. Currently unix socket is
-/// supported, but additional type (udp, tcp, https etc.) may be added later.
-/// The commands and responses are sent in JSON format.
-/// See http://kea.isc.org/wiki/StatsDesign for details.
-///
-/// In general, the command has the following format:
-/// {
-/// "command": "statistic-get",
-/// "arguments": {
-/// "name": "received-packets"
-/// }
-/// }
-///
-/// And the response is:
-///
-/// {
-/// "result": 0,
-/// "observations": {
-/// "received-packets": [ [ 1234, "2015-04-15 12:34:45.123" ] ]
-/// }
-/// }
-///
-/// CommandsMgr does not implement the commands (except one, "list-commands")
-/// itself, but rather provides an interface (see @ref registerCommand,
-/// @ref deregisterCommand, @ref processCommand) for other components to use
-/// it. The @ref CommandHandler type is specified in a way to easily use
-/// existing command handlers in DHCPv4 and DHCPv6 components.
-class CommandMgr : public boost::noncopyable {
+/// This class extends @ref BaseCommandMgr with the ability to receive and
+/// respond to commands over unix domain sockets.
+class CommandMgr : public BaseCommandMgr, public boost::noncopyable {
public:
- /// @brief Defines command handler type
- ///
- /// Command handlers are expected to use this format.
- /// @param name name of the commands
- /// @param params parameters specific to the command
- /// @return response (created with createAnswer())
- typedef boost::function<isc::data::ConstElementPtr (const std::string& name,
- const isc::data::ConstElementPtr& params)> CommandHandler;
-
/// @brief CommandMgr is a singleton class. This method returns reference
/// to its sole instance.
///
/// @brief Shuts down any open control sockets
void closeCommandSocket();
- /// @brief Registers specified command handler for a given command
- ///
- /// @param cmd name of the command to be handled
- /// @param handler pointer to the method that will handle the command
- void registerCommand(const std::string& cmd, CommandHandler handler);
-
- /// @brief Deregisters specified command handler
- ///
- /// @param cmd name of the command that's no longer handled
- void deregisterCommand(const std::string& cmd);
-
- /// @brief Triggers command processing
- ///
- /// This method processes specified command. The command is specified using
- /// a single Element. See @ref CommandMgr for description of its syntax.
- /// Typically, this method is called internally, when there's a new data
- /// received over control socket. However, in some cases (e.g. signal received)
- /// it may be called by external code explicitly. Hence this method is public.
- isc::data::ConstElementPtr processCommand(const isc::data::ConstElementPtr& cmd);
-
/// @brief Reads data from a socket, parses as JSON command and processes it
///
/// This method is used to handle traffic on connected socket. This callback
/// @param sockfd socket descriptor of a connected socket
static void commandReader(int sockfd);
- /// @brief Auxiliary method that removes all installed commands.
- ///
- /// The only unwipeable method is list-commands, which is internally
- /// handled at all times.
- void deregisterAll();
-
/// @brief Adds an information about opened connection socket
///
/// @param conn Connection socket to be stored
/// Registers internal 'list-commands' command.
CommandMgr();
- /// @brief 'list-commands' command handler
- ///
- /// This method implements command 'list-commands'. It returns a list of all
- /// currently supported commands.
- /// @param name name of the command (should always be 'list-commands')
- /// @param params additional parameters (ignored)
- /// @return structure that includes all currently supported commands
- isc::data::ConstElementPtr
- listCommandsHandler(const std::string& name,
- const isc::data::ConstElementPtr& params);
-
- typedef std::map<std::string, CommandHandler> HandlerContainer;
-
- /// @brief Container for command handlers
- HandlerContainer handlers_;
-
/// @brief Control socket structure
///
/// This is the socket that accepts incoming connections. There can be at