Commit e8f1f73d authored by Marcin Siodelski's avatar Marcin Siodelski
Browse files

[3405] Use SignalSet class to handle signals in DHCPv6 server.

parent d4dc6b5a
......@@ -77,6 +77,7 @@ b10_dhcp6_LDADD += $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la
b10_dhcp6_LDADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la
b10_dhcp6_LDADD += $(top_builddir)/src/lib/log/libkea-log.la
b10_dhcp6_LDADD += $(top_builddir)/src/lib/util/libkea-util.la
b10_dhcp6_LDADD += $(top_builddir)/src/lib/util/io/libkea-util-io.la
b10_dhcp6_LDADD += $(top_builddir)/src/lib/hooks/libkea-hooks.la
b10_dhcp6dir = $(pkgdatadir)
......
......@@ -255,6 +255,18 @@ bool Dhcpv6Srv::run() {
LOG_ERROR(dhcp6_logger, DHCP6_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 packet received
if (!query) {
......
......@@ -160,9 +160,9 @@ ControlledDhcpv6Srv::init(const std::string& file_name) {
// 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(SIGHUP, signalHandler);
signal(SIGTERM, signalHandler);
signal(SIGINT, signalHandler);
signal_set_.reset(new isc::util::io::SignalSet(SIGINT, SIGHUP, SIGTERM));
// Set the pointer to the handler function.
signal_handler_ = signalHandler;
}
void ControlledDhcpv6Srv::cleanup() {
......
......@@ -135,6 +135,7 @@ dhcp6_unittests_LDADD += $(top_builddir)/src/lib/hooks/libkea-hooks.la
dhcp6_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la
dhcp6_unittests_LDADD += $(top_builddir)/src/lib/log/libkea-log.la
dhcp6_unittests_LDADD += $(top_builddir)/src/lib/util/libkea-util.la
dhcp6_unittests_LDADD += $(top_builddir)/src/lib/util/io/libkea-util-io.la
endif
noinst_PROGRAMS = $(TESTS)
......@@ -83,6 +83,7 @@ libkea_dhcpsrv_la_LIBADD += $(top_builddir)/src/lib/dhcp_ddns/libkea-dhcp_ddns.
libkea_dhcpsrv_la_LIBADD += $(top_builddir)/src/lib/hooks/libkea-hooks.la
libkea_dhcpsrv_la_LIBADD += $(top_builddir)/src/lib/log/libkea-log.la
libkea_dhcpsrv_la_LIBADD += $(top_builddir)/src/lib/util/libkea-util.la
libkea_dhcpsrv_la_LIBADD += $(top_builddir)/src/lib/util/io/libkea-util-io.la
libkea_dhcpsrv_la_LIBADD += $(top_builddir)/src/lib/cc/libkea-cc.la
libkea_dhcpsrv_la_LIBADD += $(top_builddir)/src/lib/hooks/libkea-hooks.la
......
......@@ -15,6 +15,7 @@
#include <config.h>
#include <dhcpsrv/daemon.h>
#include <exceptions/exceptions.h>
#include <boost/bind.hpp>
#include <errno.h>
/// @brief provides default implementation for basic daemon operations
......@@ -27,7 +28,11 @@ namespace dhcp {
// This is an initial config file location.
std::string Daemon::config_file_ = "";
Daemon::Daemon() {
Daemon::Daemon()
: signal_set_(), signal_handler_() {
}
Daemon::~Daemon() {
}
void Daemon::init(const std::string& config_file) {
......@@ -42,8 +47,12 @@ void Daemon::shutdown() {
}
Daemon::~Daemon() {
void Daemon::handleSignal() {
if (signal_set_ && signal_handler_) {
signal_set_->handleNext(boost::bind(signal_handler_, _1));
}
}
};
};
......@@ -13,8 +13,9 @@
// PERFORMANCE OF THIS SOFTWARE.
#include <config.h>
#include <string>
#include <util/io/signal_set.h>
#include <boost/noncopyable.hpp>
#include <string>
namespace isc {
......@@ -44,6 +45,11 @@ namespace dhcp {
/// By default, the configuration file location is empty and its actual value
/// is assigned to the static object in @c Daemon::init function.
///
/// Classes derived from @c Daemon may install custom signal handlers using
/// @c isc::util::io::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.
......@@ -52,9 +58,16 @@ class Daemon : public boost::noncopyable {
public:
/// @brief Default constructor
///
/// Currently it does nothing.
/// Initializes the object installing custom signal handlers for the
/// process to NULL.
Daemon();
/// @brief Desctructor
///
/// Having virtual destructor ensures that all derived classes will have
/// virtual destructor as well.
virtual ~Daemon();
/// @brief Initializes the server.
///
/// Depending on the configuration backend, it establishes msgq session,
......@@ -87,12 +100,6 @@ public:
/// @brief Initiates shutdown procedure for the whole DHCPv6 server.
virtual void shutdown();
/// @brief Desctructor
///
/// Having virtual destructor ensures that all derived classes will have
/// virtual destructor as well.
virtual ~Daemon();
/// @brief Returns config file name.
static std::string getConfigFile() {
return (config_file_);
......@@ -107,6 +114,34 @@ public:
/// @param verbose verbose mode (true usually enables DEBUG messages)
static void loggerInit(const char* log_name, bool verbose);
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::io::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::io::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::io::SignalHandler signal_handler_;
private:
/// @brief Config file name or empty if config file not used.
......
......@@ -18,6 +18,7 @@
#include <exceptions/exceptions.h>
#include <boost/function.hpp>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
#include <set>
#include <signal.h>
......@@ -31,6 +32,10 @@ public:
isc::Exception(file, line, what) { };
};
class SignalSet;
typedef boost::shared_ptr<SignalSet> SignalSetPtr;
typedef boost::function<void(int signum)> SignalHandler;
class SignalSet : public boost::noncopyable {
......
......@@ -26,9 +26,9 @@ using namespace isc::util::io;
class SignalSetTest : public ::testing::Test {
public:
SignalSetTest()
: handler_calls_(0),
signum_ (-1) {
SignalSetTest() {
handler_calls_ = 0;
signum_ = -1;
}
~SignalSetTest() {
......@@ -38,21 +38,23 @@ public:
}
void handleNext() {
signal_set_->handleNext(boost::bind(&SignalSetTest::testHandler,
this, _1));
signal_set_->handleNext(boost::bind(&SignalSetTest::testHandler, _1));
}
void testHandler(int signum) {
static void testHandler(int signum) {
signum_ = signum;
++handler_calls_;
}
int handler_calls_;
int signum_;
static int handler_calls_;
static int signum_;
boost::shared_ptr<SignalSet> signal_set_;
};
int SignalSetTest::handler_calls_ = 0;
int SignalSetTest::signum_ = -1;
TEST_F(SignalSetTest, twoSignals) {
// Register handlers for two signals.
signal_set_.reset(new SignalSet(SIGHUP, SIGINT));
......@@ -90,4 +92,5 @@ TEST_F(SignalSetTest, twoSignals) {
EXPECT_NO_THROW(signal_set_->remove(SIGINT));
}
} // end of anonymous namespace
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment