From: Marcin Siodelski Date: Mon, 2 Jun 2014 16:49:10 +0000 (+0200) Subject: [3405] Use SignalSet class to handle signals in DHCPv6 server. X-Git-Tag: trac3434_base~11^2~16 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=e8f1f73d0b2c949c33e2e611b0c8f2d721401dfe;p=thirdparty%2Fkea.git [3405] Use SignalSet class to handle signals in DHCPv6 server. --- diff --git a/src/bin/dhcp6/Makefile.am b/src/bin/dhcp6/Makefile.am index 8f0dd76f12..27967e91f8 100644 --- a/src/bin/dhcp6/Makefile.am +++ b/src/bin/dhcp6/Makefile.am @@ -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) diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc index 78c2397c84..9ccb36963a 100644 --- a/src/bin/dhcp6/dhcp6_srv.cc +++ b/src/bin/dhcp6/dhcp6_srv.cc @@ -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) { diff --git a/src/bin/dhcp6/kea_controller.cc b/src/bin/dhcp6/kea_controller.cc index 33404cac58..7e578c4f6a 100644 --- a/src/bin/dhcp6/kea_controller.cc +++ b/src/bin/dhcp6/kea_controller.cc @@ -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() { diff --git a/src/bin/dhcp6/tests/Makefile.am b/src/bin/dhcp6/tests/Makefile.am index 75452db730..37c9105617 100644 --- a/src/bin/dhcp6/tests/Makefile.am +++ b/src/bin/dhcp6/tests/Makefile.am @@ -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) diff --git a/src/lib/dhcpsrv/Makefile.am b/src/lib/dhcpsrv/Makefile.am index 6044edcf3e..541e25fa0c 100644 --- a/src/lib/dhcpsrv/Makefile.am +++ b/src/lib/dhcpsrv/Makefile.am @@ -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 diff --git a/src/lib/dhcpsrv/daemon.cc b/src/lib/dhcpsrv/daemon.cc index f3b361b91a..ccf02344de 100644 --- a/src/lib/dhcpsrv/daemon.cc +++ b/src/lib/dhcpsrv/daemon.cc @@ -15,6 +15,7 @@ #include #include #include +#include #include /// @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)); + } } + }; }; diff --git a/src/lib/dhcpsrv/daemon.h b/src/lib/dhcpsrv/daemon.h index 515b168b6f..09b1c2a939 100644 --- a/src/lib/dhcpsrv/daemon.h +++ b/src/lib/dhcpsrv/daemon.h @@ -13,8 +13,9 @@ // PERFORMANCE OF THIS SOFTWARE. #include -#include +#include #include +#include 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. diff --git a/src/lib/util/io/signal_set.h b/src/lib/util/io/signal_set.h index b1c31a0c29..4fbc0e62b9 100644 --- a/src/lib/util/io/signal_set.h +++ b/src/lib/util/io/signal_set.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -31,6 +32,10 @@ public: isc::Exception(file, line, what) { }; }; +class SignalSet; + +typedef boost::shared_ptr SignalSetPtr; + typedef boost::function SignalHandler; class SignalSet : public boost::noncopyable { diff --git a/src/lib/util/io/tests/signal_set_unittest.cc b/src/lib/util/io/tests/signal_set_unittest.cc index a8ac2da2f0..a52ac25e26 100644 --- a/src/lib/util/io/tests/signal_set_unittest.cc +++ b/src/lib/util/io/tests/signal_set_unittest.cc @@ -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 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