summaryrefslogtreecommitdiffstats
path: root/src/lib/process/daemon.h
blob: 5c9b4260fa40983728b5415f5b2e3a152cac89b3 (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
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
// Copyright (C) 2014-2021 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 DAEMON_H
#define DAEMON_H

#include <cc/data.h>
#include <process/config_base.h>
#include <util/pid_file.h>
#include <util/signal_set.h>
#include <boost/noncopyable.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <string>

namespace isc {
namespace process {

/// @brief Exception thrown when the PID file points to a live PID
class DaemonPIDExists : public Exception {
public:
    DaemonPIDExists(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what) { };
};

/// @brief Base class for all services
///
/// This is the base class that all daemons (DHCPv4, DHCPv6, D2 and possibly
/// others) are derived from. It provides a standard interface for starting up,
/// reconfiguring, shutting down and several other operations. It also covers
/// some common operations.
///
/// This class is not expected to be instantiated directly, but rather daemon
/// implementations should derive from it.
///
/// Methods are not pure virtual, as we need to instantiate basic daemons (e.g.
/// Dhcpv6Srv) in tests, without going through the hassles of implementing stub
/// methods.
///
/// Classes derived from @c Daemon may install custom signal handlers using
/// @c isc::util::SignalSet class. This base class provides a declaration
/// of the @c SignalSet object that should be initialized in the derived
/// classes to install the custom exception handlers.
///
/// @note Only one instance of this class is instantiated as it encompasses
///       the whole operation of the server.  Nothing, however, enforces the
///       singleton status of the object.
class Daemon : public boost::noncopyable {

public:
    /// @brief Default constructor
    ///
    /// Initializes the object installing custom signal handlers for the
    /// process to NULL.
    Daemon();

    /// @brief Destructor
    ///
    /// Having virtual destructor ensures that all derived classes will have
    /// virtual destructor as well.
    virtual ~Daemon();

    /// @brief Performs final deconfiguration.
    ///
    /// Performs configuration backend specific final clean-up. This is called
    /// shortly before the daemon terminates. Depending on backend, it may
    /// terminate existing msgq session, close LDAP connection or similar.
    ///
    /// The daemon is not expected to receive any further commands or
    /// configuration updates as it is in final stages of shutdown.
    virtual void cleanup();

    /// @brief Initiates shutdown procedure for the whole server.
    virtual void shutdown();

    /// @brief Initializes logger
    ///
    /// This method initializes logging system. It also sets the default
    /// output to stdout. This is used in early stages of the startup
    /// phase before config file and parsed and proper logging details
    /// are known.
    ///
    /// @param log_name name used in logger initialization
    /// @param verbose verbose mode (true usually enables DEBUG messages)
    static void loggerInit(const char* log_name, bool verbose);

    /// @brief Configures logger
    ///
    /// Applies configuration stored in a top-level structure in the
    /// configuration file. This structure has a "loggers" array that
    /// contains 0 or more entries, each configuring one logging source
    /// (name, severity, debuglevel), each with zero or more outputs (file,
    /// maxsize, maximum number of files).
    ///
    /// @param log_config JSON structures that describe logging
    /// @param storage configuration will be stored here
    static void configureLogger(const isc::data::ConstElementPtr& log_config,
                                const isc::process::ConfigPtr& storage);

    /// @brief Sets or clears verbose mode
    ///
    /// Verbose mode (-v in command-line) triggers loggers to log everything
    /// (sets severity to DEBUG and debuglevel to 99). Values specified in the
    /// config file are ignored.
    ///
    /// @param verbose specifies if verbose should be set or not
    static void setVerbose(const bool verbose);

    /// @brief Returns if running in verbose mode
    ///
    /// @return verbose mode
    static bool getVerbose();

    /// @brief returns Kea version on stdout and exits.
    ///
    /// With extended == false, this method returns a simple string
    /// containing version number. With extended == true, it returns
    /// also additional information about sources. It is expected to
    /// return extra information about dependencies and used DB backends.
    ///
    /// As there is no static virtual methods in C++ this class method
    /// has to be redefined in derived classes and called with the
    /// derived class name or a child name.
    ///
    /// @param extended print additional information?
    /// @return text string
    static std::string getVersion(bool extended);

    /// @brief Returns config file name.
    /// @return text string
    std::string getConfigFile() const;

    /// @brief Sets the configuration file name
    ///
    /// @param config_file pathname of the configuration file
    void setConfigFile(const std::string& config_file);

    /// @brief Checks the configuration file name.
    /// @throw BadValue when the configuration file name is bad.
    void checkConfigFile() const;

    /// @brief Writes current configuration to specified file
    ///
    /// This method writes the current configuration to specified file.
    /// @todo: this logically more belongs to CPL process file. Once
    /// Daemon is merged with CPL architecture, it will be a better
    /// fit.
    ///
    /// If cfg is not specified, the current config (as returned by
    /// CfgMgr::instance().getCurrentCfg() will be returned.
    ///
    /// @param config_file name of the file to write the configuration to
    /// @param cfg configuration to write (optional)
    /// @return number of files written
    /// @throw Unexpected if CfgMgr can't retrieve configuration or file cannot
    ///                   be written
    virtual size_t
    writeConfigFile(const std::string& config_file,
                    isc::data::ConstElementPtr cfg = isc::data::ConstElementPtr()) const;

    /// @brief returns the process name
    /// This value is used as when forming the default PID file name
    /// @return text string
    static std::string getProcName();

    /// @brief Sets the process name
    /// @param proc_name name the process by which the process is recognized
    static void setProcName(const std::string& proc_name);

    /// @brief Returns the directory used when forming default PID file name
    /// @return text string
    std::string getPIDFileDir() const;

    /// @brief Sets the PID file directory
    /// @param pid_file_dir path into which the PID file should be written
    /// Note the value should not include a trailing slash, '/'
    void setPIDFileDir(const std::string& pid_file_dir);

    /// @brief Returns the current PID file name
    /// @return text string
    std::string getPIDFileName() const;

    /// @brief Sets PID file name
    ///
    /// If this method is called prior to calling createPIDFile,
    /// the value passed in will be treated as the full file name
    /// for the PID file.  This provides a means to override the
    /// default file name with an explicit value.
    ///
    /// @param pid_file_name file name to be used as the PID file
    void setPIDFileName(const std::string& pid_file_name);

    /// @brief Creates the PID file
    ///
    /// If the PID file name has not been previously set, the method
    /// uses manufacturePIDFileName() to set it.  If the PID file
    /// name refers to an existing file whose contents are a PID whose
    /// process is still alive, the method will throw a DaemonPIDExists
    /// exception.  Otherwise, the file created (or truncated) and
    /// the given pid (if not zero) is written to the file.
    ///
    /// @param pid PID to write to the file if not zero, otherwise the
    /// PID of the current process is used.
    void createPIDFile(int pid = 0);

    /// @brief Returns default logger name.
    static std::string getDefaultLoggerName() {
        return (default_logger_name_);
    }

    /// @brief Sets the default logger name.
    ///
    /// This name is used in cases when a user doesn't provide a configuration
    /// for logger in the Kea configuration file.
    static void setDefaultLoggerName(const std::string& logger) {
        default_logger_name_ = logger;
    }

    /// @brief Fetches the exit value.
    int getExitValue() {
        return (exit_value_);
    }

    /// @brief Sets the exit value.
    ///
    /// @param value new exit value.
    void setExitValue(int value) {
        exit_value_ = value;
    }

protected:

    /// @brief Invokes handler for the next received signal.
    ///
    /// This function provides a default implementation for the function
    /// handling next signal received by the process. It checks if a pointer
    /// to @c isc::util::SignalSet object and the signal handler function
    /// have been set. If they have been set, the signal handler is invoked for
    /// the the next signal registered in the @c SignalSet object.
    ///
    /// This function should be received in the main loop of the process.
    virtual void handleSignal();

    /// @brief A pointer to the object installing custom signal handlers.
    ///
    /// This pointer needs to be initialized to point to the @c SignalSet
    /// object in the derived classes which need to handle signals received
    /// by the process.
    isc::util::SignalSetPtr signal_set_;

    /// @brief Pointer to the common signal handler invoked by the handleSignal
    /// function.
    ///
    /// This pointer needs to be initialized to point to the signal handler
    /// function for signals being handled by the process. If signal handler
    /// it not initialized, the signals will not be handled.
    isc::util::SignalHandler signal_handler_;

    /// @brief Manufacture the pid file name
    std::string makePIDFileName() const;

    /// @brief Timestamp of the start of the daemon.
    boost::posix_time::ptime start_;

private:
    /// @brief Config file name or empty if config file not used.
    std::string config_file_;

    /// @brief Name of this process, used when creating its pid file
    static std::string proc_name_;

    /// @brief Pointer to the directory where PID file(s) are written
    /// It defaults to --localstatedir / run
    std::string pid_file_dir_;

    /// @brief Pointer to the PID file for this process
    isc::util::PIDFilePtr pid_file_;

    /// @brief Indicates whether verbose mode is turned on or not.
    static bool verbose_;

    /// @brief Stores default logger name
    static std::string default_logger_name_;

    /// @brief Flag indicating if this instance created the file
    bool am_file_author_;

    /// @brief Exit value the process should use.  Typically set
    /// by the application during a controlled shutdown.
    int exit_value_;
};

}; // end of isc::dhcp namespace
}; // end of isc namespace

#endif