36 struct CtrlDhcp4Hooks {
37 int hooks_index_dhcp4_srv_configured_;
41 hooks_index_dhcp4_srv_configured_ = HooksManager::registerHook(
"dhcp4_srv_configured");
61 void signalHandler(
int signo) {
63 if (signo == SIGHUP) {
64 ControlledDhcpv4Srv::processCommand(
"config-reload",
66 }
else if ((signo == SIGTERM) || (signo == SIGINT)) {
67 ControlledDhcpv4Srv::processCommand(
"shutdown",
80 ControlledDhcpv4Srv::init(
const std::string& file_name) {
86 string reason = comment ? comment->stringValue() :
87 "no details available";
100 signal_handler_ = signalHandler;
103 void ControlledDhcpv4Srv::cleanup() {
118 ControlledDhcpv4Srv::loadConfigFile(
const std::string& file_name) {
129 if (file_name.empty()) {
132 " Please use -c command line option.");
137 json = parser.
parseFile(file_name, Parser4Context::PARSER_DHCP4);
146 "a map, i.e., start with { and end with } and contain " 147 "at least an entry called 'Dhcp4' that itself is a map. " 149 <<
" is a valid JSON, but its top element is not a map." 150 " Did you forget to add { } around your configuration?");
154 result = ControlledDhcpv4Srv::processCommand(
"config-set", json);
160 "processCommand(\"config-set\", json)");
168 string reason = comment ? comment->stringValue() :
169 "no details available";
172 }
catch (
const std::exception& ex) {
175 CfgMgr::instance().rollback();
178 .arg(file_name).arg(ex.what());
180 << file_name <<
"': " << ex.
what());
188 ControlledDhcpv4Srv::commandShutdownHandler(
const string&,
ConstElementPtr) {
189 if (ControlledDhcpv4Srv::getInstance()) {
190 ControlledDhcpv4Srv::getInstance()->shutdown();
194 "Shutdown failure.");
202 ControlledDhcpv4Srv::commandLibReloadHandler(
const string&,
ConstElementPtr) {
207 bool status = HooksManager::loadLibraries(loaded);
211 "Failed to reload hooks libraries.");
215 "Hooks libraries successfully reloaded.");
220 ControlledDhcpv4Srv::commandConfigReloadHandler(
const string&,
224 std::string file = ControlledDhcpv4Srv::getInstance()->getConfigFile();
227 return (loadConfigFile(file));
228 }
catch (
const std::exception& ex) {
235 "Config reload failed:" +
string(ex.what())));
240 ControlledDhcpv4Srv::commandConfigGetHandler(
const string&,
242 ConstElementPtr config = CfgMgr::instance().getCurrentCfg()->toElement();
248 ControlledDhcpv4Srv::commandConfigWriteHandler(
const string&,
257 if (filename_param) {
260 "passed parameter 'filename' is not a string"));
262 filename = filename_param->stringValue();
266 if (filename.empty()) {
268 filename = getConfigFile();
271 if (filename.empty()) {
273 "Please specify filename explicitly."));
280 size = writeConfigFile(filename, cfg);
296 + filename +
" successful", params));
300 ControlledDhcpv4Srv::commandConfigSetHandler(
const string&,
311 message =
"Missing mandatory 'arguments' parameter.";
313 dhcp4 = args->get(
"Dhcp4");
315 message =
"Missing mandatory 'Dhcp4' parameter.";
317 message =
"'Dhcp4' parameter expected to be a map.";
321 if (!message.empty()) {
331 CfgMgr::instance().rollback();
339 Daemon::configureLogger(args->get(
"Logging"),
340 CfgMgr::instance().getStagingCfg());
344 CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
355 CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
358 CfgMgr::instance().commit();
363 CfgMgr::instance().getCurrentCfg()->applyLoggingCfg();
370 ControlledDhcpv4Srv::commandConfigTestHandler(
const string&,
381 message =
"Missing mandatory 'arguments' parameter.";
383 dhcp4 = args->get(
"Dhcp4");
385 message =
"Missing mandatory 'Dhcp4' parameter.";
387 message =
"'Dhcp4' parameter expected to be a map.";
391 if (!message.empty()) {
401 CfgMgr::instance().rollback();
404 return (checkConfig(dhcp4));
408 ControlledDhcpv4Srv::commandDhcpDisableHandler(
const std::string&,
410 std::ostringstream message;
411 int64_t max_period = 0;
417 message <<
"arguments for the 'dhcp-disable' command must be a map";
422 if (max_period_element) {
425 message <<
"'max-period' argument must be a number";
429 max_period = max_period_element->intValue();
430 if (max_period <= 0) {
431 message <<
"'max-period' must be positive integer";
437 network_state_->delayedEnableAll(static_cast<unsigned>(max_period));
444 if (message.tellp() == 0) {
445 network_state_->disableService();
447 message <<
"DHCPv4 service disabled";
448 if (max_period > 0) {
449 message <<
" for " << max_period <<
" seconds";
460 ControlledDhcpv4Srv::commandDhcpEnableHandler(
const std::string&,
ConstElementPtr) {
461 network_state_->enableService();
466 ControlledDhcpv4Srv::commandVersionGetHandler(
const string&,
ConstElementPtr) {
469 arguments->set(
"extended", extended);
471 Dhcpv4Srv::getVersion(
false),
477 ControlledDhcpv4Srv::commandBuildReportHandler(
const string&,
485 ControlledDhcpv4Srv::commandLeasesReclaimHandler(
const string&,
492 message =
"Missing mandatory 'remove' parameter.";
496 message =
"Missing mandatory 'remove' parameter.";
498 message =
"'remove' parameter expected to be a boolean.";
500 bool remove_lease = remove_name->boolValue();
501 server_->alloc_engine_->reclaimExpiredLeases4(0, 0, remove_lease);
503 message =
"Reclamation of expired leases is complete.";
511 ControlledDhcpv4Srv::processCommand(
const string& command,
513 string txt = args ? args->str() :
"(none)";
516 .arg(command).arg(txt);
522 "Server object not initialized, so can't process command '" +
523 command +
"', arguments: '" + txt +
"'.");
528 if (command ==
"shutdown") {
529 return (srv->commandShutdownHandler(command, args));
531 }
else if (command ==
"libreload") {
532 return (srv->commandLibReloadHandler(command, args));
534 }
else if (command ==
"config-reload") {
535 return (srv->commandConfigReloadHandler(command, args));
537 }
else if (command ==
"config-set") {
538 return (srv->commandConfigSetHandler(command, args));
540 }
else if (command ==
"config-get") {
541 return (srv->commandConfigGetHandler(command, args));
543 }
else if (command ==
"config-test") {
544 return (srv->commandConfigTestHandler(command, args));
546 }
else if (command ==
"dhcp-disable") {
547 return (srv->commandDhcpDisableHandler(command, args));
549 }
else if (command ==
"dhcp-enable") {
550 return (srv->commandDhcpEnableHandler(command, args));
552 }
else if (command ==
"version-get") {
553 return (srv->commandVersionGetHandler(command, args));
555 }
else if (command ==
"build-report") {
556 return (srv->commandBuildReportHandler(command, args));
558 }
else if (command ==
"leases-reclaim") {
559 return (srv->commandLeasesReclaimHandler(command, args));
561 }
else if (command ==
"config-write") {
562 return (srv->commandConfigWriteHandler(command, args));
566 "Unrecognized command:" + command);
570 + command +
"':" + ex.
what() +
571 ", params: '" + txt +
"'"));
584 std::ostringstream err;
587 err <<
"Server object not initialized, can't process config.";
601 }
catch (
const std::exception& ex) {
602 err <<
"Failed to process configuration:" << ex.what();
608 DatabaseConnection::db_lost_callback =
609 boost::bind(&ControlledDhcpv4Srv::dbLostCallback, srv, _1);
610 CfgDbAccessPtr cfg_db = CfgMgr::instance().getStagingCfg()->getCfgDbAccess();
611 cfg_db->setAppendedParameters(
"universe=4");
612 cfg_db->createManagers();
613 }
catch (
const std::exception& ex) {
614 err <<
"Unable to open database: " << ex.what();
621 }
catch (
const std::exception& ex) {
622 err <<
"Error starting DHCP_DDNS client after server reconfiguration: " 629 Dhcp4to6Ipc::instance().open();
630 }
catch (
const std::exception& ex) {
631 std::ostringstream err;
632 err <<
"error starting DHCPv4-over-DHCPv6 IPC " 633 " after server reconfiguration: " << ex.what();
640 qc = CfgMgr::instance().getStagingCfg()->getDHCPQueueControl();
641 if (IfaceMgr::instance().configureDHCPPacketQueue(AF_INET, qc)) {
643 .arg(IfaceMgr::instance().getPacketQueue4()->getInfoStr());
646 }
catch (
const std::exception& ex) {
647 err <<
"Error setting packet queue controls after server reconfiguration: " 659 CfgMgr::instance().getStagingCfg()->getCfgIface()->
660 openSockets(AF_INET, srv->
getPort(), getInstance()->useBroadcast());
664 CfgMgr::instance().getStagingCfg()->getCfgExpiration()->
665 setupTimers(&ControlledDhcpv4Srv::reclaimExpiredLeases,
666 &ControlledDhcpv4Srv::deleteExpiredReclaimedLeases,
669 }
catch (
const std::exception& ex) {
670 err <<
"unable to setup timers for periodically running the" 671 " reclamation of the expired leases: " 681 if (HooksManager::calloutsPresent(
Hooks.hooks_index_dhcp4_srv_configured_)) {
684 callout_handle->setArgument(
"io_context", srv->
getIOService());
686 callout_handle->setArgument(
"json_config", config);
687 callout_handle->setArgument(
"server_config", CfgMgr::instance().getStagingCfg());
689 HooksManager::callCallouts(
Hooks.hooks_index_dhcp4_srv_configured_,
708 std::ostringstream err;
711 err <<
"Server object not initialized, can't process config.";
718 ControlledDhcpv4Srv::ControlledDhcpv4Srv(uint16_t port )
722 "There is another Dhcpv4Srv instance already.");
734 CommandMgr::instance().registerCommand(
"build-report",
735 boost::bind(&ControlledDhcpv4Srv::commandBuildReportHandler,
this, _1, _2));
737 CommandMgr::instance().registerCommand(
"config-get",
738 boost::bind(&ControlledDhcpv4Srv::commandConfigGetHandler,
this, _1, _2));
740 CommandMgr::instance().registerCommand(
"config-reload",
741 boost::bind(&ControlledDhcpv4Srv::commandConfigReloadHandler,
this, _1, _2));
743 CommandMgr::instance().registerCommand(
"config-set",
744 boost::bind(&ControlledDhcpv4Srv::commandConfigSetHandler,
this, _1, _2));
746 CommandMgr::instance().registerCommand(
"config-test",
747 boost::bind(&ControlledDhcpv4Srv::commandConfigTestHandler,
this, _1, _2));
749 CommandMgr::instance().registerCommand(
"config-write",
750 boost::bind(&ControlledDhcpv4Srv::commandConfigWriteHandler,
this, _1, _2));
752 CommandMgr::instance().registerCommand(
"dhcp-enable",
753 boost::bind(&ControlledDhcpv4Srv::commandDhcpEnableHandler,
this, _1, _2));
755 CommandMgr::instance().registerCommand(
"dhcp-disable",
756 boost::bind(&ControlledDhcpv4Srv::commandDhcpDisableHandler,
this, _1, _2));
758 CommandMgr::instance().registerCommand(
"libreload",
759 boost::bind(&ControlledDhcpv4Srv::commandLibReloadHandler,
this, _1, _2));
761 CommandMgr::instance().registerCommand(
"leases-reclaim",
762 boost::bind(&ControlledDhcpv4Srv::commandLeasesReclaimHandler,
this, _1, _2));
764 CommandMgr::instance().registerCommand(
"shutdown",
765 boost::bind(&ControlledDhcpv4Srv::commandShutdownHandler,
this, _1, _2));
767 CommandMgr::instance().registerCommand(
"version-get",
768 boost::bind(&ControlledDhcpv4Srv::commandVersionGetHandler,
this, _1, _2));
771 CommandMgr::instance().registerCommand(
"statistic-get",
772 boost::bind(&StatsMgr::statisticGetHandler, _1, _2));
774 CommandMgr::instance().registerCommand(
"statistic-reset",
775 boost::bind(&StatsMgr::statisticResetHandler, _1, _2));
777 CommandMgr::instance().registerCommand(
"statistic-remove",
778 boost::bind(&StatsMgr::statisticRemoveHandler, _1, _2));
780 CommandMgr::instance().registerCommand(
"statistic-get-all",
781 boost::bind(&StatsMgr::statisticGetAllHandler, _1, _2));
783 CommandMgr::instance().registerCommand(
"statistic-reset-all",
784 boost::bind(&StatsMgr::statisticResetAllHandler, _1, _2));
786 CommandMgr::instance().registerCommand(
"statistic-remove-all",
787 boost::bind(&StatsMgr::statisticRemoveAllHandler, _1, _2));
802 DatabaseConnection::db_lost_callback = 0;
804 timer_mgr_->unregisterTimers();
807 CommandMgr::instance().closeCommandSocket();
810 CommandMgr::instance().deregisterCommand(
"build-report");
811 CommandMgr::instance().deregisterCommand(
"config-get");
812 CommandMgr::instance().deregisterCommand(
"config-reload");
813 CommandMgr::instance().deregisterCommand(
"config-test");
814 CommandMgr::instance().deregisterCommand(
"config-write");
815 CommandMgr::instance().deregisterCommand(
"leases-reclaim");
816 CommandMgr::instance().deregisterCommand(
"libreload");
817 CommandMgr::instance().deregisterCommand(
"config-set");
818 CommandMgr::instance().deregisterCommand(
"dhcp-disable");
819 CommandMgr::instance().deregisterCommand(
"dhcp-enable");
820 CommandMgr::instance().deregisterCommand(
"shutdown");
821 CommandMgr::instance().deregisterCommand(
"statistic-get");
822 CommandMgr::instance().deregisterCommand(
"statistic-get-all");
823 CommandMgr::instance().deregisterCommand(
"statistic-remove");
824 CommandMgr::instance().deregisterCommand(
"statistic-remove-all");
825 CommandMgr::instance().deregisterCommand(
"statistic-reset");
826 CommandMgr::instance().deregisterCommand(
"statistic-reset-all");
827 CommandMgr::instance().deregisterCommand(
"version-get");
839 void ControlledDhcpv4Srv::sessionReader(
void) {
848 ControlledDhcpv4Srv::reclaimExpiredLeases(
const size_t max_leases,
849 const uint16_t timeout,
850 const bool remove_lease,
851 const uint16_t max_unwarned_cycles) {
852 server_->
alloc_engine_->reclaimExpiredLeases4(max_leases, timeout,
854 max_unwarned_cycles);
860 ControlledDhcpv4Srv::deleteExpiredReclaimedLeases(
const uint32_t secs) {
868 bool reopened =
false;
873 cfg_db->createManagers();
875 }
catch (
const std::exception& ex) {
889 db_reconnect_ctl.reset();
891 if (!db_reconnect_ctl->checkRetries()) {
893 .arg(db_reconnect_ctl->maxRetries());
899 .arg(db_reconnect_ctl->maxRetries() - db_reconnect_ctl->retriesLeft() + 1)
900 .arg(db_reconnect_ctl->maxRetries())
901 .arg(db_reconnect_ctl->retryInterval());
905 boost::bind(&ControlledDhcpv4Srv::dbReconnect,
this,
907 db_reconnect_ctl->retryInterval(),
916 ControlledDhcpv4Srv::dbLostCallback(
ReconnectCtlPtr db_reconnect_ctl) {
920 if (!db_reconnect_ctl) {
927 if (!db_reconnect_ctl->retriesLeft() ||
928 !db_reconnect_ctl->retryInterval()) {
930 .arg(db_reconnect_ctl->retriesLeft())
931 .arg(db_reconnect_ctl->retryInterval());
936 dbReconnect(db_reconnect_ctl);
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
uint16_t getPort() const
Get UDP port on which server should listen.
isc::data::ElementPtr parseFile(const std::string &filename, ParserType parser_type)
Run the parser on the file specified.
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
ConstElementPtr createAnswer(const int status_code, const std::string &text, const ConstElementPtr &arg)
const int CONTROL_RESULT_SUCCESS
Status code indicating a successful operation.
Evaluation context, an interface to the expression evaluation.
void shutdown()
Instructs the server to shut down.
static CfgMgr & instance()
returns a single instance of Configuration Manager
Manages a pool of asynchronous interval timers.
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
const int CONTROL_RESULT_ERROR
Status code indicating a general failure.
boost::shared_ptr< Element > ElementPtr
SrvConfigPtr getCurrentCfg()
Returns a pointer to the current configuration.
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
isc::data::ConstElementPtr configureDhcp4Server(Dhcpv4Srv &server, isc::data::ConstElementPtr config_set, bool check_only)
Configure DHCPv4 server (Dhcpv4Srv) with a set of configuration values.
std::vector< HookLibInfo > HookLibsCollection
A storage for information about hook libraries.
isc::log::Logger dhcp4_logger(DHCP4_APP_LOGGER_NAME)
Base logger for DHCPv4 server.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
static const std::string FLUSH_RECLAIMED_TIMER_NAME
Name of the timer for flushing reclaimed leases.
asiolink::IOServicePtr & getIOService()
Returns pointer to the IO service used by the server.
~ControlledDhcpv4Srv()
Destructor.
boost::shared_ptr< CfgDbAccess > CfgDbAccessPtr
A pointer to the CfgDbAccess.
void shutdown()
Initiates shutdown procedure for the whole DHCPv4 server.
void stop()
Stop the underlying event loop.
boost::shared_ptr< const Element > ConstElementPtr
void cleanup()
Performs cleanup, immediately before termination.
Represents a collection of signals handled in a customized way.
boost::shared_ptr< AllocEngine > alloc_engine_
Allocation Engine.
void run_one()
Run the underlying event loop for a single event.
This is a base class for exceptions thrown from the DNS library module.
ConstElementPtr parseAnswer(int &rcode, const ConstElementPtr &msg)
Defines the logger used by the top-level component of kea-dhcp-ddns.
NetworkStatePtr network_state_
Holds information about disabled DHCP service and/or disabled subnet/network scopes.
isc::log::Logger logger("asiodns")
Use the ASIO logger.
void startD2()
Starts DHCP_DDNS client IO if DDNS updates are enabled.
boost::shared_ptr< CalloutHandle > CalloutHandlePtr
A shared pointer to a CalloutHandle object.
static const std::string RECLAIM_EXPIRED_TIMER_NAME
Name of the timer for reclaiming expired leases.
This file contains several functions and constants that are used for handling commands and responses ...
static ElementPtr create(const Position &pos=ZERO_POSITION())
A generic exception that is thrown if a function is called in a prohibited way.
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
static ControlledDhcpv4Srv * getInstance()
Returns pointer to the sole instance of Dhcpv4Srv.
Controlled version of the DHCPv4 server.
std::string getConfigReport()
Defines the Dhcp4o6Ipc class.
static const TimerMgrPtr & instance()
Returns pointer to the sole instance of the TimerMgr.
const int DBG_DHCP4_COMMAND
Debug level used to log receiving commands.
boost::shared_ptr< ReconnectCtl > ReconnectCtlPtr
Pointer to an instance of ReconnectCtl.
NetworkStatePtr & getNetworkState()
Returns pointer to the network state used by the server.
Contains declarations for loggers used by the DHCPv4 server component.