summaryrefslogtreecommitdiffstats
path: root/src/lib/hooks/library_handle.h
blob: 14af40c729b0504f9fb5e7e800cfff1f0d4e3e6e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
// Copyright (C) 2013-2020 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 LIBRARY_HANDLE_H
#define LIBRARY_HANDLE_H

#include <string>
#include <cc/data.h>

namespace isc {
namespace hooks {

// Forward declarations
class CalloutHandle;
class CalloutManager;

/// Typedef for a callout pointer.  (Callouts must have "C" linkage.)
extern "C" {
    typedef int (*CalloutPtr)(CalloutHandle&);
};

/// @brief Library handle
///
/// This class is accessed by the user library when registering callouts,
/// either by the library's load() function, or by one of the callouts
/// themselves.
///
/// It is really little more than a shell around the CalloutManager.  By
/// presenting this object to the user-library callouts, callouts can manage
/// the callout list for their own library, but cannot affect the callouts
/// registered by other libraries.
///
/// (This restriction is achieved by the CalloutManager maintaining the concept
/// of the "current library".  When a callout is registered - either by the
/// library's load() function, or by a callout in the library - the registration
/// information includes the library active at the time.  When that callout is
/// called, the CalloutManager uses that information to set the "current
/// library": the registration functions only operator on data whose
/// associated library is equal to the "current library".)
///
/// As of Kea 1.3.0 release, the @ref LibraryHandle can be used by the hook
/// libraries to install control command handlers and dynamically register
/// hook points with which the handlers are associated. For example, if the
/// hook library supports control-command 'foo-bar' it should register its
/// handler similarly to this:
/// @code
/// int load(LibraryHandle& libhandle) {
///     libhandle.registerCommandCallout("foo-bar", foo_bar_handler);
///     return (0);
/// }
/// @endcode
///
/// which will result in automatic creation of the hook point for the command
/// (if one doesn't exist) and associating the callout 'foo_bar_handler' with
/// this hook point as a handler for the command.

class LibraryHandle {
public:

    /// @brief Constructor
    ///
    /// @param manager Back reference to the containing CalloutManager.
    ///        This reference is used to access appropriate methods in that
    ///        object.  Note that the reference is safe - the only instance
    ///        of the LibraryHandle in the system is as a member of the
    ///        CalloutManager to which it points.
    ///
    /// @param index Index of the library to which the LibraryHandle applies.
    ///        If negative, the library index as set in the CalloutManager is
    ///        used.  Note: although -1 is a valid argument value for
    ///        @ref isc::hooks::CalloutManager::setLibraryIndex(), in this class
    ///        it is used as a sentinel to indicate that the library index in
    ///        @ref isc::hooks::CalloutManager should not be set or reset.
    LibraryHandle(CalloutManager& manager, int index = -1)
        : callout_manager_(manager), index_(index) {}

    /// @brief Register a callout on a hook
    ///
    /// Registers a callout function with a given hook.  The callout is added
    /// to the end of the callouts for the current library that are associated
    /// with that hook.
    ///
    /// @param name Name of the hook to which the callout is added.
    /// @param callout Pointer to the callout function to be registered.
    ///
    /// @throw NoSuchHook The hook name is unrecognized.
    /// @throw Unexpected The hook name is valid but an internal data structure
    ///        is of the wrong size.
    void registerCallout(const std::string& name, CalloutPtr callout);

    /// @brief Register control command handler
    ///
    /// Registers control command handler by creating a hook point for this
    /// command (if it doesn't exist) and associating the callout as a command
    /// handler. It is possible to register multiple command handlers for the
    /// same control command because command handlers are implemented as callouts.
    ///
    /// @param command_name Command name for which handler should be installed.
    /// @param callout Pointer to the command handler implemented as a callout.
    void registerCommandCallout(const std::string& command_name, CalloutPtr callout);

    /// @brief De-Register a callout on a hook
    ///
    /// Searches through the functions registered by the current library with
    /// the named hook and removes all entries matching the callout.  It does
    /// not affect callouts registered by other libraries.
    ///
    /// @param name Name of the hook from which the callout is removed.
    /// @param callout Pointer to the callout function to be removed.
    ///
    /// @return true if a one or more callouts were deregistered.
    ///
    /// @throw NoSuchHook The hook name is unrecognized.
    /// @throw Unexpected The hook name is valid but an internal data structure
    ///        is of the wrong size.
    bool deregisterCallout(const std::string& name, CalloutPtr callout);

    /// @brief Removes all callouts on a hook
    ///
    /// Removes all callouts associated with a given hook that were registered.
    /// by the current library.  It does not affect callouts that were
    /// registered by other libraries.
    ///
    /// @param name Name of the hook from which the callouts are removed.
    ///
    /// @return true if one or more callouts were deregistered.
    ///
    /// @throw NoSuchHook Thrown if the hook name is unrecognized.
    bool deregisterAllCallouts(const std::string& name);


    /// @brief Returns configuration parameter for the library.
    ///
    /// This method returns configuration parameters specified in the
    /// configuration file. Here's the example. Let's assume that there
    /// are two hook libraries configured:
    ///
    /// "hooks-libraries": [
    ///     {
    ///        "library": "/opt/charging.so",
    ///        "parameters": {}
    ///    },
    ///    {
    ///        "library": "/opt/local/notification.so",
    ///        "parameters": {
    ///            "mail": "alarm@example.com",
    ///            "floor": 42,
    ///            "debug": false,
    ///            "users": [ "alice", "bob", "charlie" ],
    ///            "header": {
    ///                "french": "bonjour",
    ///                "klingon": "yl'el"
    ///            }
    ///        }
    ///    }
    ///]
    ///
    /// The first library has no parameters, so regardless of the name
    /// specified, for that library getParameter will always return NULL.
    ///
    /// For the second parameter, depending the following calls will return:
    /// - x = getParameter("mail") will return instance of
    ///   isc::data::StringElement. The content can be accessed with
    ///   x->stringValue() and will return std::string.
    /// - x = getParameter("floor") will return an instance of isc::data::IntElement.
    ///   The content can be accessed with x->intValue() and will return int.
    /// - x = getParameter("debug") will return an instance of isc::data::BoolElement.
    ///   Its value can be accessed with x->boolValue() and will return bool.
    /// - x = getParameter("users") will return an instance of ListElement.
    ///   Its content can be accessed with the following methods:
    ///   x->size(), x->get(index)
    /// - x = getParameter("header") will return an instance of isc::data::MapElement.
    ///   Its content can be accessed with the following methods:
    ///   x->find("klingon"), x->contains("french"), x->size()
    ///
    /// For more examples and complete API, see documentation for
    /// @ref isc::data::Element class and its derivatives:
    /// - @ref isc::data::IntElement
    /// - @ref isc::data::DoubleElement
    /// - @ref isc::data::BoolElement
    /// - @ref isc::data::StringElement
    /// - @ref isc::data::ListElement
    /// - @ref isc::data::MapElement
    ///
    /// Another good way to learn how to use Element interface is to look at the
    /// unittests in data_unittests.cc.
    ///
    /// @param name text name of the parameter.
    /// @return ElementPtr representing requested parameter (may be null, if
    ///         there is no such parameter.)
    isc::data::ConstElementPtr
    getParameter(const std::string& name);

    /// @brief Get configuration parameter common code.
    ///
    /// @return configuration parameters.
    isc::data::ConstElementPtr getParameters();

    /// @brief Returns names of configuration parameters for the library.
    ///
    /// This method returns a vector of strings reflecting names of
    /// configuration parameters specified in the configuration file.
    ///
    /// @note: kept for backward compatibility.
    /// @return a vector with parameter entry names.
    std::vector<std::string> getParameterNames();

private:
    /// @brief Copy constructor
    ///
    /// Private (with no implementation) as it makes no sense to copy an object
    /// of this type.  All code receives a reference to an existing handle which
    /// is tied to a particular CalloutManager.  Creating a copy of that handle
    /// runs the risk of a "dangling pointer" to the original handle's callout
    /// manager.
    ///
    /// @param Unused - should be the object to copy.
    LibraryHandle(const LibraryHandle&);

    /// @brief Assignment operator
    ///
    /// Declared private like the copy constructor for the same reasons. It too
    /// has no implementation.
    ///
    /// @param Unused - should be the object to copy.
    LibraryHandle& operator=(const LibraryHandle&);

    /// Back pointer to the collection object for the library
    CalloutManager& callout_manager_;

    /// Library index to which this handle applies.  -1 indicates that it
    /// applies to whatever index is current in the CalloutManager.
    int index_;
};

} // namespace util
} // namespace isc

#endif // LIBRARY_HANDLE_H