/src/kea/src/lib/config/hooked_command_mgr.cc
Line | Count | Source |
1 | | // Copyright (C) 2017-2024 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 | | #include <config.h> |
8 | | |
9 | | #include <cc/command_interpreter.h> |
10 | | #include <config/hooked_command_mgr.h> |
11 | | #include <config/config_log.h> |
12 | | #include <hooks/callout_handle.h> |
13 | | #include <hooks/hooks_manager.h> |
14 | | #include <hooks/server_hooks.h> |
15 | | #include <boost/pointer_cast.hpp> |
16 | | #include <vector> |
17 | | |
18 | | using namespace isc::data; |
19 | | using namespace isc::hooks; |
20 | | |
21 | | namespace isc { |
22 | | namespace config { |
23 | | |
24 | | HookedCommandMgr::HookedCommandMgr() |
25 | 20 | : BaseCommandMgr() { |
26 | 20 | } |
27 | | |
28 | | bool |
29 | | HookedCommandMgr::delegateCommandToHookLibrary(const std::string& cmd_name, |
30 | | const ConstElementPtr& params, |
31 | | const ConstElementPtr& original_cmd, |
32 | 20.9k | ElementPtr& answer) { |
33 | | |
34 | 20.9k | ConstElementPtr hook_response; |
35 | 20.9k | if (HooksManager::commandHandlersPresent(cmd_name)) { |
36 | |
|
37 | 0 | CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle(); |
38 | | |
39 | | // Set status to normal. |
40 | 0 | callout_handle->setStatus(CalloutHandle::NEXT_STEP_CONTINUE); |
41 | | |
42 | | // Delete previously set arguments. |
43 | 0 | callout_handle->deleteAllArguments(); |
44 | |
|
45 | 0 | ConstElementPtr command = original_cmd ? original_cmd : |
46 | 0 | createCommand(cmd_name, params); |
47 | | |
48 | | // And pass it to the hook library. |
49 | 0 | callout_handle->setArgument("command", command); |
50 | 0 | callout_handle->setArgument("response", hook_response); |
51 | |
|
52 | 0 | HooksManager::callCommandHandlers(cmd_name, *callout_handle); |
53 | | |
54 | | // The callouts should set the response. |
55 | 0 | callout_handle->getArgument("response", hook_response); |
56 | |
|
57 | 0 | answer = boost::const_pointer_cast<Element>(hook_response); |
58 | |
|
59 | 0 | return (true); |
60 | 0 | } |
61 | | |
62 | 20.9k | return (false); |
63 | 20.9k | } |
64 | | |
65 | | ConstElementPtr |
66 | | HookedCommandMgr::handleCommand(const std::string& cmd_name, |
67 | | const ConstElementPtr& params, |
68 | 20.9k | const ConstElementPtr& original_cmd) { |
69 | | |
70 | | // The 'list-commands' is a special case. Hook libraries do not implement |
71 | | // this command. We determine what commands are supported by the hook |
72 | | // libraries by checking what hook points are present that have callouts |
73 | | // registered. |
74 | 20.9k | if ((cmd_name != "list-commands")) { |
75 | 20.9k | ElementPtr hook_response; |
76 | | // Check if there are any hooks libraries to process this command. |
77 | 20.9k | if (delegateCommandToHookLibrary(cmd_name, params, original_cmd, |
78 | 20.9k | hook_response)) { |
79 | | // Hooks libraries processed this command so simply return a |
80 | | // result. |
81 | 0 | return (hook_response); |
82 | 0 | } |
83 | | |
84 | 20.9k | } |
85 | | |
86 | | // If we're here it means that the callouts weren't called. We need |
87 | | // to handle the command using local Command Manager. |
88 | 20.9k | ConstElementPtr response = BaseCommandMgr::handleCommand(cmd_name, |
89 | 20.9k | params, |
90 | 20.9k | original_cmd); |
91 | | |
92 | | // If we're processing 'list-commands' command we may need to include |
93 | | // commands supported by hooks libraries in the response. |
94 | 20.9k | if (cmd_name == "list-commands") { |
95 | | // Hooks names can be used to decode what commands are supported. |
96 | 1 | const std::vector<std::string>& hooks = |
97 | 1 | ServerHooks::getServerHooksPtr()->getHookNames(); |
98 | | |
99 | | // Only update the response if there are any hooks present. |
100 | 1 | if (!hooks.empty()) { |
101 | 1 | ElementPtr hooks_commands = Element::createList(); |
102 | 27 | for (auto const& h : hooks) { |
103 | | // Try to convert hook name to command name. If non-empty |
104 | | // string is returned it means that the hook point may have |
105 | | // command handlers associated with it. Otherwise, it means that |
106 | | // existing hook points are not for command handlers but for |
107 | | // regular callouts. |
108 | 27 | std::string command_name = ServerHooks::hookToCommandName(h); |
109 | 27 | if (!command_name.empty()) { |
110 | | // Final check: are command handlers registered for this |
111 | | // hook point? If there are no command handlers associated, |
112 | | // it means that the hook library was already unloaded. |
113 | 0 | if (HooksManager::commandHandlersPresent(command_name)) { |
114 | 0 | hooks_commands->add(Element::create(command_name)); |
115 | 0 | } |
116 | 0 | } |
117 | 27 | } |
118 | | |
119 | | // If there is at least one hook point with command handlers |
120 | | // registered |
121 | | // for it, combine the lists of commands. |
122 | 1 | if (!hooks_commands->empty()) { |
123 | 0 | response = combineCommandsLists(response, createAnswer(CONTROL_RESULT_SUCCESS, hooks_commands)); |
124 | 0 | } |
125 | 1 | } |
126 | 1 | } |
127 | | |
128 | 20.9k | return (response); |
129 | 20.9k | } |
130 | | |
131 | | |
132 | | } // end of namespace isc::config |
133 | | } // end of namespace isc |