1 // Copyright (C) 2013-2020 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 <hooks/callout_handle.h>
10 #include <hooks/callout_manager.h>
11 #include <hooks/library_handle.h>
12 #include <hooks/library_manager_collection.h>
13 #include <hooks/hooks_manager.h>
14 #include <hooks/server_hooks.h>
15 
16 #include <boost/shared_ptr.hpp>
17 #include <boost/weak_ptr.hpp>
18 
19 #include <string>
20 #include <vector>
21 
22 using namespace std;
23 
24 namespace isc {
25 namespace hooks {
26 
27 // Constructor
28 
HooksManager()29 HooksManager::HooksManager() : test_mode_(false) {
30     // Nothing present, so create the collection with any empty set of
31     // libraries, and get the CalloutManager.
32     HookLibsCollection libraries;
33     lm_collection_.reset(new LibraryManagerCollection(libraries));
34     lm_collection_->loadLibraries();
35     callout_manager_ = lm_collection_->getCalloutManager();
36 }
37 
38 // Return reference to singleton hooks manager.
39 
40 HooksManager&
getHooksManager()41 HooksManager::getHooksManager() {
42     static HooksManager manager;
43     return (manager);
44 }
45 
46 // Are callouts present?
47 
48 bool
calloutsPresentInternal(int index)49 HooksManager::calloutsPresentInternal(int index) {
50     return (callout_manager_->calloutsPresent(index));
51 }
52 
53 bool
calloutsPresent(int index)54 HooksManager::calloutsPresent(int index) {
55     return (getHooksManager().calloutsPresentInternal(index));
56 }
57 
58 bool
commandHandlersPresentInternal(const std::string & command_name)59 HooksManager::commandHandlersPresentInternal(const std::string& command_name) {
60     return (callout_manager_->commandHandlersPresent(command_name));
61 }
62 
63 bool
commandHandlersPresent(const std::string & command_name)64 HooksManager::commandHandlersPresent(const std::string& command_name) {
65     return (getHooksManager().commandHandlersPresentInternal(command_name));
66 }
67 
68 // Call the callouts
69 
70 void
callCalloutsInternal(int index,CalloutHandle & handle)71 HooksManager::callCalloutsInternal(int index, CalloutHandle& handle) {
72     callout_manager_->callCallouts(index, handle);
73 }
74 
75 void
callCallouts(int index,CalloutHandle & handle)76 HooksManager::callCallouts(int index, CalloutHandle& handle) {
77     getHooksManager().callCalloutsInternal(index, handle);
78 }
79 
80 void
callCommandHandlersInternal(const std::string & command_name,CalloutHandle & handle)81 HooksManager::callCommandHandlersInternal(const std::string& command_name,
82                                           CalloutHandle& handle) {
83     callout_manager_->callCommandHandlers(command_name, handle);
84 }
85 
86 void
callCommandHandlers(const std::string & command_name,CalloutHandle & handle)87 HooksManager::callCommandHandlers(const std::string& command_name,
88                                   CalloutHandle& handle) {
89     getHooksManager().callCommandHandlersInternal(command_name, handle);
90 }
91 
92 // Load the libraries.  This will delete the previously-loaded libraries
93 // (if present) and load new ones. If loading libraries fails, initialize with
94 // empty list.
95 
96 bool
loadLibrariesInternal(const HookLibsCollection & libraries)97 HooksManager::loadLibrariesInternal(const HookLibsCollection& libraries) {
98     if (test_mode_) {
99         return (true);
100     }
101 
102     ServerHooks::getServerHooks().getParkingLotsPtr()->clear();
103 
104     // Keep a weak pointer on the existing library manager collection.
105     boost::weak_ptr<LibraryManagerCollection> weak_lmc(lm_collection_);
106 
107     // Create the library manager collection.
108     lm_collection_.reset(new LibraryManagerCollection(libraries));
109 
110     // If there was another owner the previous library manager collection
111     // was not destroyed and libraries not closed.
112     if (!weak_lmc.expired()) {
113         isc_throw(LibrariesStillOpened, "some libraries are still opened");
114     }
115 
116     // Load the libraries.
117     bool status = lm_collection_->loadLibraries();
118 
119     if (status) {
120         // ... and obtain the callout manager for them if successful.
121         callout_manager_ = lm_collection_->getCalloutManager();
122     } else {
123         // Unable to load libraries, reset to state before this function was
124         // called.
125         static_cast<void>(unloadLibrariesInternal());
126     }
127 
128     return (status);
129 }
130 
131 bool
loadLibraries(const HookLibsCollection & libraries)132 HooksManager::loadLibraries(const HookLibsCollection& libraries) {
133     return (getHooksManager().loadLibrariesInternal(libraries));
134 }
135 
136 // Unload the libraries.  This just deletes all internal objects (which will
137 // cause the libraries to be unloaded) and initializes them with empty list if
138 // requested.
139 
140 bool
unloadLibrariesInternal()141 HooksManager::unloadLibrariesInternal() {
142     if (test_mode_) {
143         return (true);
144     }
145 
146     ServerHooks::getServerHooks().getParkingLotsPtr()->clear();
147 
148     // Keep a weak pointer on the existing library manager collection.
149     boost::weak_ptr<LibraryManagerCollection> weak_lmc(lm_collection_);
150 
151     // Create the collection with any empty set of libraries.
152     HookLibsCollection libraries;
153     lm_collection_.reset(new LibraryManagerCollection(libraries));
154 
155     // If there was another owner the previous library manager collection
156     // was not destroyed and libraries not closed.
157     boost::shared_ptr<LibraryManagerCollection> still_here = weak_lmc.lock();
158     if (still_here) {
159         // Restore the library manager collection.
160         lm_collection_ = still_here;
161         return (false);
162     }
163 
164     // Load the empty set of libraries.
165     lm_collection_->loadLibraries();
166 
167     // Get the CalloutManager.
168     callout_manager_ = lm_collection_->getCalloutManager();
169 
170     return (true);
171 }
172 
173 bool
unloadLibraries()174 HooksManager::unloadLibraries() {
175     return (getHooksManager().unloadLibrariesInternal());
176 }
177 
178 void
prepareUnloadLibrariesInternal()179 HooksManager::prepareUnloadLibrariesInternal() {
180     if (test_mode_) {
181         return;
182     }
183 
184     static_cast<void>(lm_collection_->prepareUnloadLibraries());
185 }
186 
187 void
prepareUnloadLibraries()188 HooksManager::prepareUnloadLibraries() {
189     getHooksManager().prepareUnloadLibrariesInternal();
190 }
191 
192 // Create a callout handle
193 
194 boost::shared_ptr<CalloutHandle>
createCalloutHandleInternal()195 HooksManager::createCalloutHandleInternal() {
196     return (boost::make_shared<CalloutHandle>(callout_manager_, lm_collection_));
197 }
198 
199 boost::shared_ptr<CalloutHandle>
createCalloutHandle()200 HooksManager::createCalloutHandle() {
201     return (getHooksManager().createCalloutHandleInternal());
202 }
203 
204 // Get the list of the names of loaded libraries.
205 
206 std::vector<std::string>
getLibraryNamesInternal() const207 HooksManager::getLibraryNamesInternal() const {
208     return (lm_collection_->getLibraryNames());
209 }
210 
211 HookLibsCollection
getLibraryInfoInternal() const212 HooksManager::getLibraryInfoInternal() const {
213     return (lm_collection_->getLibraryInfo());
214 }
215 
216 std::vector<std::string>
getLibraryNames()217 HooksManager::getLibraryNames() {
218     return (getHooksManager().getLibraryNamesInternal());
219 }
220 
221 HookLibsCollection
getLibraryInfo()222 HooksManager::getLibraryInfo() {
223     return (getHooksManager().getLibraryInfoInternal());
224 }
225 
226 // Shell around ServerHooks::registerHook()
227 
228 int
registerHook(const std::string & name)229 HooksManager::registerHook(const std::string& name) {
230     return (ServerHooks::getServerHooks().registerHook(name));
231 }
232 
233 // Return pre- and post- library handles.
234 
235 isc::hooks::LibraryHandle&
preCalloutsLibraryHandleInternal()236 HooksManager::preCalloutsLibraryHandleInternal() {
237     return (callout_manager_->getPreLibraryHandle());
238 }
239 
240 isc::hooks::LibraryHandle&
preCalloutsLibraryHandle()241 HooksManager::preCalloutsLibraryHandle() {
242     return (getHooksManager().preCalloutsLibraryHandleInternal());
243 }
244 
245 isc::hooks::LibraryHandle&
postCalloutsLibraryHandleInternal()246 HooksManager::postCalloutsLibraryHandleInternal() {
247     return (callout_manager_->getPostLibraryHandle());
248 }
249 
250 isc::hooks::LibraryHandle&
postCalloutsLibraryHandle()251 HooksManager::postCalloutsLibraryHandle() {
252     return (getHooksManager().postCalloutsLibraryHandleInternal());
253 }
254 
255 // Validate libraries
256 
257 std::vector<std::string>
validateLibraries(const std::vector<std::string> & libraries)258 HooksManager::validateLibraries(const std::vector<std::string>& libraries) {
259     return (LibraryManagerCollection::validateLibraries(libraries));
260 }
261 
262 // Test mode
263 
264 void
setTestMode(bool mode)265 HooksManager::setTestMode(bool mode) {
266     getHooksManager().test_mode_ = mode;
267 }
268 
269 bool
getTestMode()270 HooksManager::getTestMode() {
271     return (getHooksManager().test_mode_);
272 }
273 
274 } // namespace util
275 } // namespace isc
276