Kea  2.5.2
dhcp4/main.cc
Go to the documentation of this file.
1 // Copyright (C) 2011-2023 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 
10 #include <dhcp4/ctrl_dhcp4_srv.h>
11 #include <dhcp4/dhcp4_log.h>
12 #include <dhcp4/parser_context.h>
14 #include <dhcpsrv/cfgmgr.h>
15 #include <exceptions/exceptions.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 
26 using namespace isc::data;
27 using namespace isc::dhcp;
28 using namespace isc::process;
29 using namespace std;
30 
39 
40 namespace {
41 
42 const char* const DHCP4_NAME = "kea-dhcp4";
43 
47 void
48 usage() {
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 
72 int
73 main(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  while ((ch = getopt(argc, argv, "dvVWc:p:P:t:T:")) != -1) {
87  switch (ch) {
88  case 'd':
89  verbose_mode = true;
90  break;
91 
92  case 'v':
93  cout << Dhcpv4Srv::getVersion(false) << endl;
94  return (EXIT_SUCCESS);
95 
96  case 'V':
97  cout << Dhcpv4Srv::getVersion(true) << endl;
98  return (EXIT_SUCCESS);
99 
100  case 'W':
101  cout << isc::detail::getConfigReport() << endl;
102  return (EXIT_SUCCESS);
103 
104  case 'T':
105  load_hooks = true;
106  check_mode = true;
107  config_file = optarg;
108  break;
109 
110  case 't':
111  check_mode = true;
112  config_file = optarg;
113  break;
114 
115  case 'c': // config file
116  config_file = optarg;
117  break;
118 
119  case 'p': // server port number
120  try {
121  server_port_number = boost::lexical_cast<int>(optarg);
122  } catch (const boost::bad_lexical_cast &) {
123  cerr << "Failed to parse server port number: [" << optarg
124  << "], 1-65535 allowed." << endl;
125  usage();
126  }
127  if (server_port_number <= 0 || server_port_number > 65535) {
128  cerr << "Failed to parse server port number: [" << optarg
129  << "], 1-65535 allowed." << endl;
130  usage();
131  }
132  break;
133 
134  case 'P': // client port number
135  try {
136  client_port_number = boost::lexical_cast<int>(optarg);
137  } catch (const boost::bad_lexical_cast &) {
138  cerr << "Failed to parse client port number: [" << optarg
139  << "], 1-65535 allowed." << endl;
140  usage();
141  }
142  if (client_port_number <= 0 || client_port_number > 65535) {
143  cerr << "Failed to parse client port number: [" << optarg
144  << "], 1-65535 allowed." << endl;
145  usage();
146  }
147  break;
148 
149  default:
150  usage();
151  }
152  }
153 
154  // Check for extraneous parameters.
155  if (argc > optind) {
156  usage();
157  }
158 
159  // Configuration file is required.
160  if (config_file.empty()) {
161  cerr << "Configuration file not specified." << endl;
162  usage();
163  }
164 
165  // This is the DHCPv4 server
166  CfgMgr::instance().setFamily(AF_INET);
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);
173  Daemon::setDefaultLoggerName(DHCP4_ROOT_LOGGER_NAME);
174  Daemon::loggerInit(DHCP4_ROOT_LOGGER_NAME, verbose_mode);
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.
222  Daemon::setDefaultLoggerName(DHCP4_ROOT_LOGGER_NAME);
223 
224  // Initialize logging. If verbose, we'll use maximum verbosity.
225  Daemon::loggerInit(DHCP4_ROOT_LOGGER_NAME, verbose_mode);
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 }
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
Controlled version of the DHCPv4 server.
void init(const std::string &config_file)
Initializes the server.
int run()
Main server processing loop.
Definition: dhcp4_srv.cc:1003
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.
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.
Definition: log/logger.cc:208
Exception thrown when the PID file points to a live PID.
Definition: daemon.h:25
static void setVerbose(const bool verbose)
Sets or clears verbose mode.
Definition: daemon.cc:79
static void setProcName(const std::string &proc_name)
Sets the process name.
Definition: daemon.cc:134
void createPIDFile(int pid=0)
Creates the PID file.
Definition: daemon.cc:202
void setConfigFile(const std::string &config_file)
Sets the configuration file name.
Definition: daemon.cc:109
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