summaryrefslogtreecommitdiffstats
path: root/src/lib/hooks/server_hooks.h
blob: 9fc60bcdcea8f51954bc499c5c4dc65c9651eec4 (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
// Copyright (C) 2013-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/.

#ifndef SERVER_HOOKS_H
#define SERVER_HOOKS_H

#include <exceptions/exceptions.h>

#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>

#include <map>
#include <string>
#include <vector>

namespace isc {
namespace hooks {

/// @brief Duplicate hook
///
/// Thrown if an attempt is made to register a hook with the same name as a
/// previously-registered hook.
class DuplicateHook : public Exception {
public:
    DuplicateHook(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what) {}
};

/// @brief Invalid hook
///
/// Thrown if an attempt is made to get the index for an invalid hook.
class NoSuchHook : public Exception {
public:
    NoSuchHook(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what) {}
};

class ServerHooks;
typedef boost::shared_ptr<ServerHooks> ServerHooksPtr;

/// @brief Server hook collection
///
/// This class is used by the server-side code to register hooks - points in the
/// server processing at which libraries can register functions (callouts) that
/// the server will call.  These functions can modify data and so affect the
/// processing of the server.
///
/// The ServerHooks class is little more than a wrapper around the std::map
/// class.  It stores a hook, assigning to it a unique index number.  This
/// number is then used by the server code to identify the hook being called.
/// (Although it would be feasible to use a name as an index, using an integer
/// will speed up the time taken to locate the callouts, which may make a
/// difference in a frequently-executed piece of code.)
///
/// ServerHooks is a singleton object and is only accessible by the static
/// method getServerHooks().

class ServerHooks : public boost::noncopyable {
public:

    /// Index numbers for pre-defined hooks.
    static const int CONTEXT_CREATE = 0;
    static const int CONTEXT_DESTROY = 1;

    /// @brief Reset to Initial State
    ///
    /// Resets the collection of hooks to the initial state, with just the
    /// context_create and context_destroy hooks set.  This used during
    /// testing to reset the global ServerHooks object; it should never be
    /// used in production.
    ///
    /// @throws isc::Unexpected if the registration of the pre-defined hooks
    ///         fails in some way.
    void reset();

    /// @brief Register a hook
    ///
    /// Registers a hook and returns the hook index.
    ///
    /// @param name Name of the hook
    ///
    /// @return Index of the hook, to be used in subsequent hook-related calls.
    ///         This will be greater than or equal to zero (so allowing a
    ///         negative value to indicate an invalid index).
    ///
    /// @throws DuplicateHook A hook with the same name has already been
    ///         registered.
    int registerHook(const std::string& name);

    /// @brief Get hook name
    ///
    /// Returns the name of a hook given the index.  This is most likely to be
    /// used in log messages.
    ///
    /// @param index Index of the hook
    ///
    /// @return Name of the hook.
    ///
    /// @throw NoSuchHook if the hook index is invalid.
    std::string getName(int index) const;

    /// @brief Get hook index
    ///
    /// Returns the index of a hook.
    ///
    /// @param name Name of the hook
    ///
    /// @return Index of the hook, to be used in subsequent calls.
    ///
    /// @throw NoSuchHook if the hook name is unknown to the caller.
    int getIndex(const std::string& name) const;

    /// @brief Find hook index
    ///
    /// Provides exception safe method of retrieving an index of the
    /// specified hook.
    ///
    /// @param name Name of the hook
    ///
    /// @return Index of the hook if the hook point exists, or -1 if the
    /// hook point doesn't exist.
    int findIndex(const std::string& name) const;

    /// @brief Return number of hooks
    ///
    /// Returns the total number of hooks registered.
    ///
    /// @return Number of hooks registered.
    int getCount() const {
        return (hooks_.size());
    }

    /// @brief Get hook names
    ///
    /// Return list of hooks registered in the object.
    ///
    /// @return Vector of strings holding hook names.
    std::vector<std::string> getHookNames() const;

    /// @brief Return ServerHooks object
    ///
    /// Returns the global ServerHooks object.
    ///
    /// @return Reference to the global ServerHooks object.
    static ServerHooks& getServerHooks();

    /// @brief Returns pointer to ServerHooks object.
    ///
    /// @return Pointer to the global ServerHooks object.
    static ServerHooksPtr getServerHooksPtr();

    /// @brief Generates hook point name for the given control command name.
    ///
    /// This function is called to generate the name of the hook point
    /// when the hook point is used to install command handlers for the
    /// given control command.
    ///
    /// The name of the hook point is generated as follows:
    /// - command name is prefixed with a dollar sign,
    /// - all hyphens are replaced with underscores.
    ///
    /// For example, if the command_name is 'foo-bar', the resulting hook
    /// point name will be '$foo_bar'.
    ///
    /// @param command_name Command name for which the hook point name is
    ///        to be generated.
    ///
    /// @return Hook point name, or an empty string if the command name
    /// can't be converted to a hook name (e.g. when it lacks dollar sign).
    static std::string commandToHookName(const std::string& command_name);

    /// @brief Returns command name for a specified hook name.
    ///
    /// This function removes leading dollar sign and replaces underscores
    /// with hyphens.
    ///
    /// @param hook_name Hook name for which command name should be returned.
    ///
    /// @return Command name.
    static std::string hookToCommandName(const std::string& hook_name);

private:
    /// @brief Constructor
    ///
    /// This pre-registers two hooks, context_create and context_destroy, which
    /// are called by the server before processing a packet and after processing
    /// for the packet has completed.  They allow the server code to allocate
    /// and destroy per-packet context.
    ///
    /// The constructor is declared private to enforce the singleton nature of
    /// the object.  A reference to the singleton is obtainable through the
    /// getServerHooks() static method.
    ///
    /// @throws isc::Unexpected if the registration of the pre-defined hooks
    ///         fails in some way.
    ServerHooks();

    /// @brief Initialize hooks
    ///
    /// Sets the collection of hooks to the initial state, with just the
    /// context_create and context_destroy hooks set.  This is used during
    /// construction.
    ///
    /// @throws isc::Unexpected if the registration of the pre-defined hooks
    ///         fails in some way.
    void initialize();

    /// Useful typedefs.
    typedef std::map<std::string, int> HookCollection;
    typedef std::map<int, std::string> InverseHookCollection;

    /// Two maps, one for name->index, the other for index->name.  (This is
    /// simpler than using a multi-indexed container.)
    HookCollection  hooks_;                 ///< Hook name/index collection
    InverseHookCollection inverse_hooks_;   ///< Hook index/name collection
};

} // namespace util
} // namespace isc

#endif  // SERVER_HOOKS_H