summaryrefslogtreecommitdiffstats
path: root/src/lib/config/hooked_command_mgr.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/config/hooked_command_mgr.cc')
-rw-r--r--src/lib/config/hooked_command_mgr.cc131
1 files changed, 131 insertions, 0 deletions
diff --git a/src/lib/config/hooked_command_mgr.cc b/src/lib/config/hooked_command_mgr.cc
new file mode 100644
index 0000000000..c7c2e3df2b
--- /dev/null
+++ b/src/lib/config/hooked_command_mgr.cc
@@ -0,0 +1,131 @@
+// 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/hooked_command_mgr.h>
+#include <config/config_log.h>
+#include <hooks/callout_handle.h>
+#include <hooks/hooks_manager.h>
+#include <hooks/server_hooks.h>
+#include <boost/pointer_cast.hpp>
+#include <vector>
+
+using namespace isc::data;
+using namespace isc::hooks;
+
+namespace isc {
+namespace config {
+
+HookedCommandMgr::HookedCommandMgr()
+ : BaseCommandMgr() {
+}
+
+bool
+HookedCommandMgr::delegateCommandToHookLibrary(const std::string& cmd_name,
+ const ConstElementPtr& params,
+ const ConstElementPtr& original_cmd,
+ ElementPtr& answer) {
+
+ ConstElementPtr hook_response;
+ if (HooksManager::commandHandlersPresent(cmd_name)) {
+
+ CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
+
+ // Set status to normal.
+ callout_handle->setStatus(CalloutHandle::NEXT_STEP_CONTINUE);
+
+ // Delete previously set arguments.
+ callout_handle->deleteAllArguments();
+
+ ConstElementPtr command = original_cmd ? original_cmd :
+ createCommand(cmd_name, params);
+
+ // And pass it to the hook library.
+ callout_handle->setArgument("command", command);
+ callout_handle->setArgument("response", hook_response);
+
+ HooksManager::callCommandHandlers(cmd_name, *callout_handle);
+
+ // The callouts should set the response.
+ callout_handle->getArgument("response", hook_response);
+
+ answer = boost::const_pointer_cast<Element>(hook_response);
+
+ return (true);
+ }
+
+ return (false);
+}
+
+ConstElementPtr
+HookedCommandMgr::handleCommand(const std::string& cmd_name,
+ const ConstElementPtr& params,
+ const ConstElementPtr& original_cmd) {
+
+ // The 'list-commands' is a special case. Hook libraries do not implement
+ // this command. We determine what commands are supported by the hook
+ // libraries by checking what hook points are present that have callouts
+ // registered.
+ if ((cmd_name != "list-commands")) {
+ ElementPtr hook_response;
+ // Check if there are any hooks libraries to process this command.
+ if (delegateCommandToHookLibrary(cmd_name, params, original_cmd,
+ hook_response)) {
+ // Hooks libraries processed this command so simply return a
+ // result.
+ return (hook_response);
+ }
+
+ }
+
+ // If we're here it means that the callouts weren't called. We need
+ // to handle the command using local Command Mananger.
+ ConstElementPtr response = BaseCommandMgr::handleCommand(cmd_name,
+ params,
+ original_cmd);
+
+ // If we're processing 'list-commands' command we may need to include
+ // commands supported by hooks libraries in the response.
+ if (cmd_name == "list-commands") {
+ // Hooks names can be used to decode what commands are supported.
+ const std::vector<std::string>& hooks =
+ ServerHooks::getServerHooksPtr()->getHookNames();
+
+ // Only update the response if there are any hooks present.
+ if (!hooks.empty()) {
+ ElementPtr hooks_commands = Element::createList();
+ for (auto h = hooks.cbegin(); h != hooks.end(); ++h) {
+ // Try to convert hook name to command name. If non-empty
+ // string is returned it means that the hook point may have
+ // command handlers associated with it. Otherwise, it means that
+ // existing hook points are not for command handlers but for
+ // regular callouts.
+ std::string command_name = ServerHooks::hookToCommandName(*h);
+ if (!command_name.empty()) {
+ // Final check: are command handlers registered for this
+ // hook point? If there are no command handlers associated,
+ // it means that the hook library was already unloaded.
+ if (HooksManager::commandHandlersPresent(command_name)) {
+ hooks_commands->add(Element::create(command_name));
+ }
+ }
+ }
+
+ // If there is at least one hook point with command handlers
+ // registered
+ // for it, combine the lists of commands.
+ if (!hooks_commands->empty()) {
+ response = combineCommandsLists(response, createAnswer(0, hooks_commands));
+ }
+ }
+ }
+
+ return (response);
+}
+
+
+} // end of namespace isc::config
+} // end of namespace isc