From: Marcin Siodelski Date: Tue, 3 Jun 2014 10:08:23 +0000 (+0200) Subject: [3405] Install signal handlers in DHCPv4 server. X-Git-Tag: trac3434_base~11^2~11 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=db9b5842fcc548510429f5a3f189ac87f6369993;p=thirdparty%2Fkea.git [3405] Install signal handlers in DHCPv4 server. --- diff --git a/src/bin/dhcp4/dhcp4_messages.mes b/src/bin/dhcp4/dhcp4_messages.mes index 9777391b37..0f41447ad8 100644 --- a/src/bin/dhcp4/dhcp4_messages.mes +++ b/src/bin/dhcp4/dhcp4_messages.mes @@ -97,6 +97,14 @@ This error message is logged when the attempt to compute DHCID for a specified lease has failed. The lease details and reason for failure is logged in the message. +% DHCP4_DYNAMIC_RECONFIGURATION initate server reconfiguration using file: %1, after receiving SIGHUP signal +This is the info message logged when the DHCPv4 server starts reconfiguration +as a result of receiving SIGHUP signal. + +% DHCP4_DYNAMIC_RECONFIGURATION_FAIL dynamic server reconfiguration failed with file: %1 +This is an error message logged when the dynamic reconfiguration of the +DHCP server failed. + % DHCP4_EMPTY_HOSTNAME received empty hostname from the client, skipping processing of this option This debug message is issued when the server received an empty Hostname option from a client. Server does not process empty Hostname options and therefore diff --git a/src/bin/dhcp4/dhcp4_srv.cc b/src/bin/dhcp4/dhcp4_srv.cc index 60b5a35c06..d5e69df615 100644 --- a/src/bin/dhcp4/dhcp4_srv.cc +++ b/src/bin/dhcp4/dhcp4_srv.cc @@ -175,6 +175,18 @@ Dhcpv4Srv::run() { LOG_ERROR(dhcp4_logger, DHCP4_PACKET_RECEIVE_FAIL).arg(e.what()); } + // Handle next signal received by the process. It must be called after + // an attempt to receive a packet to properly handle server shut down. + // The SIGTERM or SIGINT will be received prior to, or during execution + // of select() (select is invoked by recivePacket()). When that happens, + // select will be interrupted. The signal handler will be invoked + // immediately after select(). The handler will set the shutdown flag + // and cause the process to terminate before the next select() function + // is called. If the function was called before receivePacket the + // process could wait up to the duration of timeout of select() to + // terminate. + handleSignal(); + // Timeout may be reached or signal received, which breaks select() // with no reception ocurred if (!query) { diff --git a/src/bin/dhcp4/kea_controller.cc b/src/bin/dhcp4/kea_controller.cc index a8d43e8362..bfc4b7ca3f 100644 --- a/src/bin/dhcp4/kea_controller.cc +++ b/src/bin/dhcp4/kea_controller.cc @@ -25,11 +25,18 @@ using namespace isc::asiolink; using namespace isc::dhcp; using namespace std; -namespace isc { -namespace dhcp { - -void -ControlledDhcpv4Srv::init(const std::string& file_name) { +namespace { + +/// @brief Configure DHCPv4 server using the configuration file specified. +/// +/// This function is used to both configure the DHCP server on its startup +/// and dynamically reconfigure the server when SIGHUP signal is received. +/// +/// It fetches DHCPv6 server's configuration from the 'Dhcp4' section of +/// the JSON configuration file. +/// +/// @param file_name Configuration file location. +void configure(const std::string& file_name) { // This is a configuration backend implementation that reads the // configuration from a JSON file. @@ -41,8 +48,8 @@ ControlledDhcpv4Srv::init(const std::string& file_name) { try { if (file_name.empty()) { // Basic sanity check: file name must not be empty. - isc_throw(BadValue, "JSON configuration file not specified. Please " - "use -c command line option."); + isc_throw(isc::BadValue, "JSON configuration file not specified." + " Please use -c command line option."); } // Read contents of the file and parse it as JSON @@ -51,8 +58,8 @@ ControlledDhcpv4Srv::init(const std::string& file_name) { if (!json) { LOG_ERROR(dhcp4_logger, DHCP4_CONFIG_LOAD_FAIL) .arg("Config file " + file_name + " missing or empty."); - isc_throw(BadValue, "Unable to process JSON configuration file:" - + file_name); + isc_throw(isc::BadValue, "Unable to process JSON configuration" + " file: " << file_name); } // Get Dhcp4 component from the config @@ -60,29 +67,30 @@ ControlledDhcpv4Srv::init(const std::string& file_name) { if (!dhcp4) { LOG_ERROR(dhcp4_logger, DHCP4_CONFIG_LOAD_FAIL) - .arg("Config file " + file_name + " does not include 'Dhcp4' entry."); - isc_throw(BadValue, "Unable to process JSON configuration file:" - + file_name); + .arg("Config file " + file_name + " does not include 'Dhcp4'" + " entry."); + isc_throw(isc::BadValue, "Unable to process JSON configuration" + " file: " << file_name); } // Use parsed JSON structures to configure the server - result = processCommand("config-reload", dhcp4); + result = ControlledDhcpv4Srv::processCommand("config-reload", dhcp4); } catch (const std::exception& ex) { LOG_ERROR(dhcp4_logger, DHCP4_CONFIG_LOAD_FAIL).arg(ex.what()); - isc_throw(BadValue, "Unable to process JSON configuration file:" - + file_name); + isc_throw(isc::BadValue, "Unable to process JSON configuration file: " + << file_name); } if (!result) { // Undetermined status of the configuration. This should never happen, - // but as the configureDhcp4Server returns a pointer, it is theoretically - // possible that it will return NULL. + // but as the configureDhcp4Server returns a pointer, it is + // theoretically possible that it will return NULL. LOG_ERROR(dhcp4_logger, DHCP4_CONFIG_LOAD_FAIL) .arg("Configuration failed: Undefined result of processCommand(" "config-reload, " + file_name + ")"); - isc_throw(BadValue, "Configuration failed: Undefined result of " - "processCommand('config-reload', " + file_name + ")"); + isc_throw(isc::BadValue, "Configuration failed: Undefined result of " + "processCommand('config-reload', " << file_name << ")"); } // Now check is the returned result is successful (rcode=0) or not @@ -95,12 +103,64 @@ ControlledDhcpv4Srv::init(const std::string& file_name) { reason = string(" (") + comment->stringValue() + string(")"); } LOG_ERROR(dhcp4_logger, DHCP4_CONFIG_LOAD_FAIL).arg(reason); - isc_throw(BadValue, "Failed to apply configuration:" << reason); + isc_throw(isc::BadValue, "Failed to apply configuration: " << reason); } +} + +/// @brief Signals handler for DHCPv4 server. +/// +/// This signal handler handles the following signals received by the DHCPv4 +/// server process: +/// - SIGHUP - triggers server's dynamic reconfiguration. +/// - SIGTERM - triggers server's shut down. +/// - SIGINT - triggers server's shut down. +/// +/// @param signo Signal number received. +void signalHandler(int signo) { + // SIGHUP signals a request to reconfigure the server. + if (signo == SIGHUP) { + // Get configuration file name. + std::string file = ControlledDhcpv4Srv::getInstance()->getConfigFile(); + try { + LOG_INFO(dhcp4_logger, DHCP4_DYNAMIC_RECONFIGURATION).arg(file); + configure(file); + } catch (const std::exception& ex) { + // Log the unsuccessful reconfiguration. The reason for failure + // should be already logged. Don't rethrow an exception so as + // the server keeps working. + LOG_ERROR(dhcp4_logger, DHCP4_DYNAMIC_RECONFIGURATION_FAIL) + .arg(file); + } + } else if ((signo == SIGTERM) || (signo == SIGINT)) { + isc::data::ElementPtr params(new isc::data::MapElement()); + ControlledDhcpv4Srv::processCommand("shutdown", params); + } +} + +} + +namespace isc { +namespace dhcp { + +void +ControlledDhcpv4Srv::init(const std::string& file_name) { + // Call parent class's init to initialize file name. + Daemon::init(file_name); + + // Configure the server using JSON file. + configure(file_name); // We don't need to call openActiveSockets() or startD2() as these // methods are called in processConfig() which is called by // processCommand("reload-config", ...) + + // Set signal handlers. When the SIGHUP is received by the process + // the server reconfiguration will be triggered. When SIGTERM or + // SIGINT will be received, the server will start shutting down. + signal_set_.reset(new isc::util::io::SignalSet(SIGINT, SIGHUP, SIGTERM)); + // Set the pointer to the handler function. + signal_handler_ = signalHandler; + } void ControlledDhcpv4Srv::cleanup() {