kea_controller.cc 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. // Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this
  5. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. #include <config.h>
  7. #include <asiolink/asiolink.h>
  8. #include <dhcpsrv/cfgmgr.h>
  9. #include <dhcpsrv/parsers/dhcp_config_parser.h>
  10. #include <dhcp6/json_config_parser.h>
  11. #include <dhcp6/ctrl_dhcp6_srv.h>
  12. #include <dhcp6/dhcp6_log.h>
  13. #include <exceptions/exceptions.h>
  14. #include <signal.h>
  15. #include <string>
  16. using namespace isc::asiolink;
  17. using namespace isc::dhcp;
  18. using namespace std;
  19. namespace {
  20. /// @brief Configure DHCPv6 server using the configuration file specified.
  21. ///
  22. /// This function is used to both configure the DHCP server on its startup
  23. /// and dynamically reconfigure the server when SIGHUP signal is received.
  24. ///
  25. /// It fetches DHCPv6 server's configuration from the 'Dhcp6' section of
  26. /// the JSON configuration file.
  27. ///
  28. /// @param file_name Configuration file location.
  29. void configure(const std::string& file_name) {
  30. // This is a configuration backend implementation that reads the
  31. // configuration from a JSON file.
  32. // We are starting the configuration process so we should remove any
  33. // staging configuration that has been created during previous
  34. // configuration attempts.
  35. CfgMgr::instance().rollback();
  36. isc::data::ConstElementPtr json;
  37. isc::data::ConstElementPtr dhcp6;
  38. isc::data::ConstElementPtr logger;
  39. isc::data::ConstElementPtr result;
  40. // Basic sanity check: file name must not be empty.
  41. try {
  42. if (file_name.empty()) {
  43. // Basic sanity check: file name must not be empty.
  44. isc_throw(isc::BadValue, "JSON configuration file not specified. Please "
  45. "use -c command line option.");
  46. }
  47. // Read contents of the file and parse it as JSON
  48. json = isc::data::Element::fromJSONFile(file_name, true);
  49. if (!json) {
  50. isc_throw(isc::BadValue, "no configuration found");
  51. }
  52. // Let's do sanity check before we call json->get() which
  53. // works only for map.
  54. if (json->getType() != isc::data::Element::map) {
  55. isc_throw(isc::BadValue, "Configuration file is expected to be "
  56. "a map, i.e., start with { and end with } and contain "
  57. "at least an entry called 'Dhcp6' that itself is a map. "
  58. << file_name
  59. << " is a valid JSON, but its top element is not a map."
  60. " Did you forget to add { } around your configuration?");
  61. }
  62. // Use parsed JSON structures to configure the server
  63. result = ControlledDhcpv6Srv::processCommand("set-config", json);
  64. if (!result) {
  65. // Undetermined status of the configuration. This should never
  66. // happen, but as the configureDhcp6Server returns a pointer, it is
  67. // theoretically possible that it will return NULL.
  68. isc_throw(isc::BadValue, "undefined result of "
  69. "processCommand(\"set-config\", dhcp6)");
  70. }
  71. // Now check is the returned result is successful (rcode=0) or not
  72. // (see @ref isc::config::parseAnswer).
  73. int rcode;
  74. isc::data::ConstElementPtr comment =
  75. isc::config::parseAnswer(rcode, result);
  76. if (rcode != 0) {
  77. string reason = comment ? comment->stringValue() :
  78. "no details available";
  79. isc_throw(isc::BadValue, reason);
  80. }
  81. } catch (const std::exception& ex) {
  82. // If configuration failed at any stage, we drop the staging
  83. // configuration and continue to use the previous one.
  84. CfgMgr::instance().rollback();
  85. LOG_ERROR(dhcp6_logger, DHCP6_CONFIG_LOAD_FAIL)
  86. .arg(file_name).arg(ex.what());
  87. isc_throw(isc::BadValue, "configuration error using file '"
  88. << file_name << "': " << ex.what());
  89. }
  90. }
  91. /// @brief Signals handler for DHCPv6 server.
  92. ///
  93. /// This signal handler handles the following signals received by the DHCPv6
  94. /// server process:
  95. /// - SIGHUP - triggers server's dynamic reconfiguration.
  96. /// - SIGTERM - triggers server's shut down.
  97. /// - SIGINT - triggers server's shut down.
  98. ///
  99. /// @param signo Signal number received.
  100. void signalHandler(int signo) {
  101. // SIGHUP signals a request to reconfigure the server.
  102. if (signo == SIGHUP) {
  103. // Get configuration file name.
  104. std::string file = ControlledDhcpv6Srv::getInstance()->getConfigFile();
  105. try {
  106. LOG_INFO(dhcp6_logger, DHCP6_DYNAMIC_RECONFIGURATION).arg(file);
  107. configure(file);
  108. } catch (const std::exception& ex) {
  109. // Log the unsuccessful reconfiguration. The reason for failure
  110. // should be already logged. Don't rethrow an exception so as
  111. // the server keeps working.
  112. LOG_ERROR(dhcp6_logger, DHCP6_DYNAMIC_RECONFIGURATION_FAIL)
  113. .arg(file);
  114. }
  115. } else if ((signo == SIGTERM) || (signo == SIGINT)) {
  116. isc::data::ElementPtr params(new isc::data::MapElement());
  117. ControlledDhcpv6Srv::processCommand("shutdown", params);
  118. }
  119. }
  120. }
  121. namespace isc {
  122. namespace dhcp {
  123. void
  124. ControlledDhcpv6Srv::init(const std::string& file_name) {
  125. // Configure the server using JSON file.
  126. configure(file_name);
  127. // We don't need to call openActiveSockets() or startD2() as these
  128. // methods are called in processConfig() which is called by
  129. // processCommand("reload-config", ...)
  130. // Set signal handlers. When the SIGHUP is received by the process
  131. // the server reconfiguration will be triggered. When SIGTERM or
  132. // SIGINT will be received, the server will start shutting down.
  133. signal_set_.reset(new isc::util::SignalSet(SIGINT, SIGHUP, SIGTERM));
  134. // Set the pointer to the handler function.
  135. signal_handler_ = signalHandler;
  136. }
  137. void ControlledDhcpv6Srv::cleanup() {
  138. // Nothing to do here. No need to disconnect from anything.
  139. }
  140. };
  141. };