Kea 2.7.5
dhcp4/main.cc
Go to the documentation of this file.
1// Copyright (C) 2011-2024 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#include <kea_version.h>
9
11#include <dhcp4/dhcp4_log.h>
14#include <dhcpsrv/cfgmgr.h>
16#include <log/logger_support.h>
17#include <log/logger_manager.h>
18#include <log/output_option.h>
20#include <process/daemon.h>
21
22#include <boost/lexical_cast.hpp>
23
24#include <iostream>
25
26using namespace isc::data;
27using namespace isc::dhcp;
28using namespace isc::process;
29using namespace std;
30
39
40namespace {
41
42const char* const DHCP4_NAME = "kea-dhcp4";
43
47void
48usage() {
49 cerr << "Kea DHCPv4 server, "
50 << "version " << VERSION
51 << " (" << PACKAGE_VERSION_TYPE << ")"
52 << endl;
53 cerr << endl;
54 cerr << "Usage: " << DHCP4_NAME
55 << " -[v|V|W] [-d] [-{c|t|T} cfgfile] [-p number] [-P number]" << endl;
56 cerr << " -v: print version number and exit" << endl;
57 cerr << " -V: print extended version and exit" << endl;
58 cerr << " -W: display the configuration report and exit" << endl;
59 cerr << " -d: debug mode with extra verbosity (former -v)" << endl;
60 cerr << " -c file: specify configuration file" << endl;
61 cerr << " -t file: check the configuration file syntax and exit" << endl;
62 cerr << " -T file: check the configuration file doing hooks load and extra "
63 << "checks and exit" << endl;
64 cerr << " -p number: specify non-standard server port number 1-65535 "
65 << "(useful for testing only)" << endl;
66 cerr << " -P number: specify non-standard client port number 1-65535 "
67 << "(useful for testing only)" << endl;
68 exit(EXIT_FAILURE);
69}
70} // namespace
71
72int
73main(int argc, char* argv[]) {
74 int ch;
75 // The default. Any other values are useful for testing only.
76 int server_port_number = DHCP4_SERVER_PORT;
77 // Not zero values are useful for testing only.
78 int client_port_number = 0;
79 bool verbose_mode = false; // Should server be verbose?
80 bool check_mode = false; // Check syntax
81 bool load_hooks = false; // Check hooks config
82
83 // The standard config file
84 std::string config_file("");
85
86 // This is the DHCPv4 server
87 CfgMgr::instance().setFamily(AF_INET);
88
89 while ((ch = getopt(argc, argv, "dvVWc:p:P:t:T:")) != -1) {
90 switch (ch) {
91 case 'd':
92 verbose_mode = true;
93 break;
94
95 case 'v':
96 cout << Dhcpv4Srv::getVersion(false) << endl;
97 return (EXIT_SUCCESS);
98
99 case 'V':
100 cout << Dhcpv4Srv::getVersion(true) << endl;
101 return (EXIT_SUCCESS);
102
103 case 'W':
104 cout << isc::detail::getConfigReport() << endl;
105 return (EXIT_SUCCESS);
106
107 case 'T':
108 load_hooks = true;
109 check_mode = true;
110 config_file = optarg;
111 break;
112
113 case 't':
114 check_mode = true;
115 config_file = optarg;
116 break;
117
118 case 'c': // config file
119 config_file = optarg;
120 break;
121
122 case 'p': // server port number
123 try {
124 server_port_number = boost::lexical_cast<int>(optarg);
125 } catch (const boost::bad_lexical_cast &) {
126 cerr << "Failed to parse server port number: [" << optarg
127 << "], 1-65535 allowed." << endl;
128 usage();
129 }
130 if (server_port_number <= 0 || server_port_number > 65535) {
131 cerr << "Failed to parse server port number: [" << optarg
132 << "], 1-65535 allowed." << endl;
133 usage();
134 }
135 break;
136
137 case 'P': // client port number
138 try {
139 client_port_number = boost::lexical_cast<int>(optarg);
140 } catch (const boost::bad_lexical_cast &) {
141 cerr << "Failed to parse client port number: [" << optarg
142 << "], 1-65535 allowed." << endl;
143 usage();
144 }
145 if (client_port_number <= 0 || client_port_number > 65535) {
146 cerr << "Failed to parse client port number: [" << optarg
147 << "], 1-65535 allowed." << endl;
148 usage();
149 }
150 break;
151
152 default:
153 usage();
154 }
155 }
156
157 // Check for extraneous parameters.
158 if (argc > optind) {
159 usage();
160 }
161
162 // Configuration file is required.
163 if (config_file.empty()) {
164 cerr << "Configuration file not specified." << endl;
165 usage();
166 }
167
168 if (check_mode) {
169 try {
170 // We need to initialize logging, in case any error messages are to be printed.
171 // This is just a test, so we don't care about lockfile.
172 setenv("KEA_LOCKFILE_DIR", "none", 0);
175
176 // Check the syntax first.
177 Parser4Context parser;
178 ConstElementPtr json;
179 json = parser.parseFile(config_file, Parser4Context::PARSER_DHCP4);
180 if (!json) {
181 cerr << "No configuration found" << endl;
182 return (EXIT_FAILURE);
183 }
184 if (verbose_mode) {
185 cerr << "Syntax check OK" << endl;
186 }
187
188 // Check the logic next.
189 ConstElementPtr dhcp4 = json->get("Dhcp4");
190 if (!dhcp4) {
191 cerr << "Missing mandatory Dhcp4 element" << endl;
192 return (EXIT_FAILURE);
193 }
194 ControlledDhcpv4Srv server(0);
195 ConstElementPtr answer;
196
197 server.setProcName(DHCP4_NAME);
198
199 // Now we pass the Dhcp4 configuration to the server, but
200 // tell it to check the configuration only (check_only = true)
201 answer = configureDhcp4Server(server, dhcp4, true, load_hooks);
202
203 int status_code = 0;
204 answer = isc::config::parseAnswer(status_code, answer);
205 if (status_code == 0) {
206 return (EXIT_SUCCESS);
207 } else {
208 cerr << "Error encountered: " << answer->stringValue() << endl;
209 return (EXIT_FAILURE);
210 }
211 } catch (const std::exception& ex) {
212 cerr << "Syntax check failed with: " << ex.what() << endl;
213 }
214 return (EXIT_FAILURE);
215 }
216
217 int ret = EXIT_SUCCESS;
218 try {
219 // It is important that we set a default logger name because this name
220 // will be used when the user doesn't provide the logging configuration
221 // in the Kea configuration file.
223
224 // Initialize logging. If verbose, we'll use maximum verbosity.
227 .arg(getpid())
228 .arg(server_port_number)
229 .arg(client_port_number)
230 .arg(verbose_mode ? "yes" : "no");
231
233 .arg(VERSION)
234 .arg(PACKAGE_VERSION_TYPE);
235
236 if (string(PACKAGE_VERSION_TYPE) == "development") {
238 }
239
240 // Create the server instance.
241 ControlledDhcpv4Srv server(server_port_number, client_port_number);
242
243 // Remember verbose-mode
244 server.setVerbose(verbose_mode);
245
246 // Create our PID file.
247 server.setProcName(DHCP4_NAME);
248 server.setConfigFile(config_file);
249 server.createPIDFile();
250
251 try {
252 // Initialize the server.
253 server.init(config_file);
254 } catch (const std::exception& ex) {
255
256 // Let's log out what went wrong.
257 try {
258 // Log with the current logger, but only if it's not
259 // configured with console output so as to not log twice.
261 LOG_ERROR(dhcp4_logger, DHCP4_INIT_FAIL).arg(ex.what());
262 }
263
264 // Log on the console as well.
265 isc::log::LoggerManager log_manager;
266 log_manager.process();
267 LOG_ERROR(dhcp4_logger, DHCP4_INIT_FAIL).arg(ex.what());
268 } catch (...) {
269 // The exception thrown during the initialization could
270 // originate from logger subsystem. Therefore LOG_ERROR()
271 // may fail as well.
272 cerr << "Failed to initialize server: " << ex.what() << endl;
273 }
274
275 return (EXIT_FAILURE);
276 }
277
278 // Tell the admin we are ready to process packets
279 LOG_INFO(dhcp4_logger, DHCP4_STARTED).arg(VERSION);
280
281 // And run the main loop of the server.
282 ret = server.run();
283
285
286 } catch (const isc::process::DaemonPIDExists& ex) {
287 // First, we print the error on stderr (that should always work)
288 cerr << DHCP4_NAME << " already running? " << ex.what()
289 << endl;
290
291 // Let's also try to log it using logging system, but we're not
292 // sure if it's usable (the exception may have been thrown from
293 // the logger subsystem)
294 try {
296 .arg(DHCP4_NAME).arg(ex.what());
297 } catch (...) {
298 // Already logged so ignore
299 }
300 ret = EXIT_FAILURE;
301 } catch (const std::exception& ex) {
302 // First, we print the error on stderr (that should always work)
303 cerr << DHCP4_NAME << ": Fatal error during start up: " << ex.what()
304 << endl;
305
306 // Let's also try to log it using logging system, but we're not
307 // sure if it's usable (the exception may have been thrown from
308 // the logger subsystem)
309 try {
311 } catch (...) {
312 // Already logged so ignore
313 }
314 ret = EXIT_FAILURE;
315 } catch (...) {
316 cerr << DHCP4_NAME << ": Fatal error during start up"
317 << endl;
318 ret = EXIT_FAILURE;
319 }
320
321 return (ret);
322}
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition cfgmgr.cc:25
Controlled version of the DHCPv4 server.
static std::string getVersion(bool extended)
returns Kea version on stdout and exit.
Evaluation context, an interface to the expression evaluation.
isc::data::ElementPtr parseFile(const std::string &filename, ParserType parser_type)
Run the parser on the file specified.
@ PARSER_DHCP4
This parser will parse the content as Dhcp4 config wrapped in a map (that's the regular config file)
void process(T start, T finish)
Process Specifications.
bool hasAppender(OutputOption::Destination const destination)
Check if this logger has an appender of the given type.
Exception thrown when the PID file points to a live PID.
Definition daemon.h:25
static void loggerInit(const char *log_name, bool verbose)
Initializes logger.
Definition daemon.cc:88
static void setDefaultLoggerName(const std::string &logger)
Sets the default logger name.
Definition daemon.h:215
int main(int argc, char *argv[])
Definition dhcp4/main.cc:73
Contains declarations for loggers used by the DHCPv4 server component.
void usage()
Print Usage.
Logging initialization functions.
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition macros.h:32
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition macros.h:20
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
Definition macros.h:26
#define LOG_FATAL(LOGGER, MESSAGE)
Macro to conveniently test fatal output and log it.
Definition macros.h:38
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition macros.h:14
ConstElementPtr parseAnswer(int &rcode, const ConstElementPtr &msg)
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:29
std::string getConfigReport()
Definition cfgrpt.cc:20
const char * DHCP4_ROOT_LOGGER_NAME
Defines the name of the root level (default) logger.
Definition dhcp4_log.cc:26
const isc::log::MessageID DHCP4_ALREADY_RUNNING
const isc::log::MessageID DHCP4_STARTED
const isc::log::MessageID DHCP4_START_INFO
const isc::log::MessageID DHCP4_SERVER_FAILED
const isc::log::MessageID DHCP4_INIT_FAIL
isc::data::ConstElementPtr configureDhcp4Server(Dhcpv4Srv &server, isc::data::ConstElementPtr config_set, bool check_only, bool extra_checks)
Configure DHCPv4 server (Dhcpv4Srv) with a set of configuration values.
const isc::log::MessageID DHCP4_SHUTDOWN
const isc::log::MessageID DHCP4_STARTING
isc::log::Logger dhcp4_logger(DHCP4_APP_LOGGER_NAME)
Base logger for DHCPv4 server.
Definition dhcp4_log.h:90
const isc::log::MessageID DHCP4_DEVELOPMENT_VERSION
const int DBG_DHCP4_START
Debug level used to log information during server startup.
Definition dhcp4_log.h:24