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)
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) {
// 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() {
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)
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
#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
// 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) {
}
-Daemon::~Daemon() {
+void Daemon::handleSignal() {
+ if (signal_set_ && signal_handler_) {
+ signal_set_->handleNext(boost::bind(signal_handler_, _1));
+ }
}
+
};
};
// PERFORMANCE OF THIS SOFTWARE.
#include <config.h>
-#include <string>
+#include <util/io/signal_set.h>
#include <boost/noncopyable.hpp>
+#include <string>
namespace isc {
/// 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.
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,
/// @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_);
/// @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.
#include <exceptions/exceptions.h>
#include <boost/function.hpp>
#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
#include <set>
#include <signal.h>
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 {
class SignalSetTest : public ::testing::Test {
public:
- SignalSetTest()
- : handler_calls_(0),
- signum_ (-1) {
+ SignalSetTest() {
+ handler_calls_ = 0;
+ signum_ = -1;
}
~SignalSetTest() {
}
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));
EXPECT_NO_THROW(signal_set_->remove(SIGINT));
}
+
} // end of anonymous namespace