]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[3405] Use SignalSet class to handle signals in DHCPv6 server.
authorMarcin Siodelski <marcin@isc.org>
Mon, 2 Jun 2014 16:49:10 +0000 (18:49 +0200)
committerMarcin Siodelski <marcin@isc.org>
Tue, 3 Jun 2014 09:12:07 +0000 (11:12 +0200)
src/bin/dhcp6/Makefile.am
src/bin/dhcp6/dhcp6_srv.cc
src/bin/dhcp6/kea_controller.cc
src/bin/dhcp6/tests/Makefile.am
src/lib/dhcpsrv/Makefile.am
src/lib/dhcpsrv/daemon.cc
src/lib/dhcpsrv/daemon.h
src/lib/util/io/signal_set.h
src/lib/util/io/tests/signal_set_unittest.cc

index 8f0dd76f1240d885b15f25dabba9f8c090d15b40..27967e91f8368dd4b07f1cf47ef8b78535335df5 100644 (file)
@@ -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)
index 78c2397c8480786c41276a4b0133ed16a83f7e28..9ccb36963af4a298dcda4328c752018ccd7d91d2 100644 (file)
@@ -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) {
index 33404cac58b3169535a6dd73885f0915c6d7e084..7e578c4f6ac96e48d925f9f69d10a8a1b27f1a03 100644 (file)
@@ -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() {
index 75452db730e69a2460a11c568c2a495abd639a89..37c91056174d5d37b1d11abd5c694c233d7f138d 100644 (file)
@@ -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)
index 6044edcf3e7dcae173451c1adb44964293092b89..541e25fa0cea2ed36efd3c254a79cfbe691262a7 100644 (file)
@@ -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
 
index f3b361b91a5b36679b25d5867fd0cb8fde11427a..ccf02344de4f8ec18f7a4b846fb51fb73608ad70 100644 (file)
@@ -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));
+    }
 }
 
+
 };
 };
index 515b168b6f8f07374ee80caa375616587b1ba71a..09b1c2a93943eae3ad54a157c03baf32d04a2a08 100644 (file)
@@ -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.
index b1c31a0c2913d7567ca1418154caf2b1903ffcbc..4fbc0e62b9d9b4198fd7077de5c747eec5bcded8 100644 (file)
@@ -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 {
index a8ac2da2f0d074e65214ad846d02fba31e04839f..a52ac25e26c7a726a31b389de7ac63e9bca10020 100644 (file)
@@ -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