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 #ifndef LIBRARY_HANDLE_H
8 #define LIBRARY_HANDLE_H
9 
10 #include <string>
11 #include <cc/data.h>
12 
13 namespace isc {
14 namespace hooks {
15 
16 // Forward declarations
17 class CalloutHandle;
18 class CalloutManager;
19 
20 /// Typedef for a callout pointer.  (Callouts must have "C" linkage.)
21 extern "C" {
22     typedef int (*CalloutPtr)(CalloutHandle&);
23 };
24 
25 /// @brief Library handle
26 ///
27 /// This class is accessed by the user library when registering callouts,
28 /// either by the library's load() function, or by one of the callouts
29 /// themselves.
30 ///
31 /// It is really little more than a shell around the CalloutManager.  By
32 /// presenting this object to the user-library callouts, callouts can manage
33 /// the callout list for their own library, but cannot affect the callouts
34 /// registered by other libraries.
35 ///
36 /// (This restriction is achieved by the CalloutManager maintaining the concept
37 /// of the "current library".  When a callout is registered - either by the
38 /// library's load() function, or by a callout in the library - the registration
39 /// information includes the library active at the time.  When that callout is
40 /// called, the CalloutManager uses that information to set the "current
41 /// library": the registration functions only operator on data whose
42 /// associated library is equal to the "current library".)
43 ///
44 /// As of Kea 1.3.0 release, the @ref LibraryHandle can be used by the hook
45 /// libraries to install control command handlers and dynamically register
46 /// hook points with which the handlers are associated. For example, if the
47 /// hook library supports control-command 'foo-bar' it should register its
48 /// handler similarly to this:
49 /// @code
50 /// int load(LibraryHandle& libhandle) {
51 ///     libhandle.registerCommandCallout("foo-bar", foo_bar_handler);
52 ///     return (0);
53 /// }
54 /// @endcode
55 ///
56 /// which will result in automatic creation of the hook point for the command
57 /// (if one doesn't exist) and associating the callout 'foo_bar_handler' with
58 /// this hook point as a handler for the command.
59 
60 class LibraryHandle {
61 public:
62 
63     /// @brief Constructor
64     ///
65     /// @param manager Back reference to the containing CalloutManager.
66     ///        This reference is used to access appropriate methods in that
67     ///        object.  Note that the reference is safe - the only instance
68     ///        of the LibraryHandle in the system is as a member of the
69     ///        CalloutManager to which it points.
70     ///
71     /// @param index Index of the library to which the LibraryHandle applies.
72     ///        If negative, the library index as set in the CalloutManager is
73     ///        used.  Note: although -1 is a valid argument value for
74     ///        @ref isc::hooks::CalloutManager::setLibraryIndex(), in this class
75     ///        it is used as a sentinel to indicate that the library index in
76     ///        @ref isc::hooks::CalloutManager should not be set or reset.
77     LibraryHandle(CalloutManager& manager, int index = -1)
callout_manager_(manager)78         : callout_manager_(manager), index_(index) {}
79 
80     /// @brief Register a callout on a hook
81     ///
82     /// Registers a callout function with a given hook.  The callout is added
83     /// to the end of the callouts for the current library that are associated
84     /// with that hook.
85     ///
86     /// @param name Name of the hook to which the callout is added.
87     /// @param callout Pointer to the callout function to be registered.
88     ///
89     /// @throw NoSuchHook The hook name is unrecognized.
90     /// @throw Unexpected The hook name is valid but an internal data structure
91     ///        is of the wrong size.
92     void registerCallout(const std::string& name, CalloutPtr callout);
93 
94     /// @brief Register control command handler
95     ///
96     /// Registers control command handler by creating a hook point for this
97     /// command (if it doesn't exist) and associating the callout as a command
98     /// handler. It is possible to register multiple command handlers for the
99     /// same control command because command handlers are implemented as callouts.
100     ///
101     /// @param command_name Command name for which handler should be installed.
102     /// @param callout Pointer to the command handler implemented as a callout.
103     void registerCommandCallout(const std::string& command_name, CalloutPtr callout);
104 
105     /// @brief De-Register a callout on a hook
106     ///
107     /// Searches through the functions registered by the current library with
108     /// the named hook and removes all entries matching the callout.  It does
109     /// not affect callouts registered by other libraries.
110     ///
111     /// @param name Name of the hook from which the callout is removed.
112     /// @param callout Pointer to the callout function to be removed.
113     ///
114     /// @return true if a one or more callouts were deregistered.
115     ///
116     /// @throw NoSuchHook The hook name is unrecognized.
117     /// @throw Unexpected The hook name is valid but an internal data structure
118     ///        is of the wrong size.
119     bool deregisterCallout(const std::string& name, CalloutPtr callout);
120 
121     /// @brief Removes all callouts on a hook
122     ///
123     /// Removes all callouts associated with a given hook that were registered.
124     /// by the current library.  It does not affect callouts that were
125     /// registered by other libraries.
126     ///
127     /// @param name Name of the hook from which the callouts are removed.
128     ///
129     /// @return true if one or more callouts were deregistered.
130     ///
131     /// @throw NoSuchHook Thrown if the hook name is unrecognized.
132     bool deregisterAllCallouts(const std::string& name);
133 
134 
135     /// @brief Returns configuration parameter for the library.
136     ///
137     /// This method returns configuration parameters specified in the
138     /// configuration file. Here's the example. Let's assume that there
139     /// are two hook libraries configured:
140     ///
141     /// "hooks-libraries": [
142     ///     {
143     ///        "library": "/opt/charging.so",
144     ///        "parameters": {}
145     ///    },
146     ///    {
147     ///        "library": "/opt/local/notification.so",
148     ///        "parameters": {
149     ///            "mail": "alarm@example.com",
150     ///            "floor": 42,
151     ///            "debug": false,
152     ///            "users": [ "alice", "bob", "charlie" ],
153     ///            "header": {
154     ///                "french": "bonjour",
155     ///                "klingon": "yl'el"
156     ///            }
157     ///        }
158     ///    }
159     ///]
160     ///
161     /// The first library has no parameters, so regardless of the name
162     /// specified, for that library getParameter will always return NULL.
163     ///
164     /// For the second parameter, depending the following calls will return:
165     /// - x = getParameter("mail") will return instance of
166     ///   isc::data::StringElement. The content can be accessed with
167     ///   x->stringValue() and will return std::string.
168     /// - x = getParameter("floor") will return an instance of isc::data::IntElement.
169     ///   The content can be accessed with x->intValue() and will return int.
170     /// - x = getParameter("debug") will return an instance of isc::data::BoolElement.
171     ///   Its value can be accessed with x->boolValue() and will return bool.
172     /// - x = getParameter("users") will return an instance of ListElement.
173     ///   Its content can be accessed with the following methods:
174     ///   x->size(), x->get(index)
175     /// - x = getParameter("header") will return an instance of isc::data::MapElement.
176     ///   Its content can be accessed with the following methods:
177     ///   x->find("klingon"), x->contains("french"), x->size()
178     ///
179     /// For more examples and complete API, see documentation for
180     /// @ref isc::data::Element class and its derivatives:
181     /// - @ref isc::data::IntElement
182     /// - @ref isc::data::DoubleElement
183     /// - @ref isc::data::BoolElement
184     /// - @ref isc::data::StringElement
185     /// - @ref isc::data::ListElement
186     /// - @ref isc::data::MapElement
187     ///
188     /// Another good way to learn how to use Element interface is to look at the
189     /// unittests in data_unittests.cc.
190     ///
191     /// @param name text name of the parameter.
192     /// @return ElementPtr representing requested parameter (may be null, if
193     ///         there is no such parameter.)
194     isc::data::ConstElementPtr
195     getParameter(const std::string& name);
196 
197     /// @brief Get configuration parameter common code.
198     ///
199     /// @return configuration parameters.
200     isc::data::ConstElementPtr getParameters();
201 
202     /// @brief Returns names of configuration parameters for the library.
203     ///
204     /// This method returns a vector of strings reflecting names of
205     /// configuration parameters specified in the configuration file.
206     ///
207     /// @note: kept for backward compatibility.
208     /// @return a vector with parameter entry names.
209     std::vector<std::string> getParameterNames();
210 
211 private:
212     /// @brief Copy constructor
213     ///
214     /// Private (with no implementation) as it makes no sense to copy an object
215     /// of this type.  All code receives a reference to an existing handle which
216     /// is tied to a particular CalloutManager.  Creating a copy of that handle
217     /// runs the risk of a "dangling pointer" to the original handle's callout
218     /// manager.
219     ///
220     /// @param Unused - should be the object to copy.
221     LibraryHandle(const LibraryHandle&);
222 
223     /// @brief Assignment operator
224     ///
225     /// Declared private like the copy constructor for the same reasons. It too
226     /// has no implementation.
227     ///
228     /// @param Unused - should be the object to copy.
229     LibraryHandle& operator=(const LibraryHandle&);
230 
231     /// Back pointer to the collection object for the library
232     CalloutManager& callout_manager_;
233 
234     /// Library index to which this handle applies.  -1 indicates that it
235     /// applies to whatever index is current in the CalloutManager.
236     int index_;
237 };
238 
239 } // namespace util
240 } // namespace isc
241 
242 #endif // LIBRARY_HANDLE_H
243